2013-05-01 80 views
3

我正在尝试将一个遗留项目置于测试中。代码的编写方式通常是可测试的,但某些第三方依赖关系不是。我试图总结我的周围,看起来如何进行单元测试是这样的头:单元测试作业组件C#

class InsightEmailJob : NHibernateJob 
{ 
    public IInsightEmailService InsightEmailService { get; set; } 
    public IReportService ReportService { get; set; } 
    public ITemplatedNotifier TemplatedNotifier { get; set; } 
    public string ReplyEmail { get; set; } 
    public string ReplyName { get; set; } 

    public InsightEmailJob(ISession session, 
     ILog log, 
     IInsightEmailService insightEmailService, 
     IReportService reportService, 
     ITemplatedNotifier templatedNotifier, 
     SystemReplyEmailSpec systemReplyEmailSpec) 
     : base(session, log) 
    { 
     InsightEmailService = insightEmailService; 
     ReportService = reportService; 
     TemplatedNotifier = templatedNotifier; 
     ReplyEmail = systemReplyEmailSpec.ReplyEmail; 
     ReplyName = systemReplyEmailSpec.ReplyName; 
    } 

    public int AccountID{ get; set; } 
    private Account mAccount; 

    public Account Account 
    { 
     get 
     { 
      if (this.mAccount == null) 
      { 
       mAccount = this.InsightEmailService.Get<Account>(AccountID); 
      } 
      return mAccount; 
     } 
    } 


    protected override void DoWork(JobExecutionContext context) 
    { 
     var insightEmail = InsightEmailService.FindAndIncrementEmailForAccount(Account); 
     var report = ReportService.LoadMultiReportByName(insightEmail.ReportName); 
     var reportData = ReportService.Execute(report, new ParameterValuesDictionary(Account, DateTime.Now.AddDays(-7), DateTime.Now, 0)); 
     var templateData = new Hashtable {{"data", reportData}, {"account", Account}}; 
     foreach (var u in Account.Users.Where(x => x.Notify)) 
     { 
      TemplatedNotifier.Send(u.UserName, ReplyName, ReplyEmail, insightEmail.TemplateName, templateData); 
     } 
    } 
} 

据我了解,很多人会建议使用嘲笑或存根在传递,而不是接口,但是我有点困惑,这实际上是有益的。看起来,这样做只会确保调用适当的方法,这让我觉得有些空洞,并且与作业的实现相关联成为一个非常有效的测试。最终问题就变成了,你如何单元测试不返回值的东西,而只是在没有按照你说的方式进行测试的情况下进行测试才会产生副作用?

回答

0

当你做单元测试时,你只是测试单元。它意味着在给定的外部依赖关系下,单元如何(例如调用其他服务的方法)。因此,如果您的测试代码的行为正确,您需要查看各种外部依赖条件。

对方法,返回什么有多种方法,如果你使用的是模拟框架来验证这个

  1. ,比方说起订量,您可以使用验证,以确保外部方法与适当的呼叫参数。
  2. 您可以验证什么是传递到使用回调(MOQ具有良好的回拨机制)的外部方法
0

单位编写测试来证明你实现正常工作。如果你的测试代码变得越来越复杂,而且事情变得越来越难以模拟,那么实现代码可能变得越来越复杂和难以理解。

当你决定在嘲笑依赖关系中有太多的工作时,你应该重新考虑你的设计,并且旨在将它重构为一个更简单的表单。

只要看看你的构造函数,我们就可以看到它可能做了太多的工作。你有6个依赖关系,你将不得不模拟所有这些来编写有效的单元测试。我不认为你有足够的抽象,因为你必须处理NHibernate会话,一些报告服务和发送电子邮件。

Repository Pattern是抽象数据访问代码的常见模式。您还应该将电子邮件发送部分移至其他课程并在此处使用其界面。

模拟没有返回值的方法很容易。通过嘲笑这些方法调用,您可以证明您的类正确使用外部依赖关系。您可以为参数值编写断言,以及调用验证代码的次数。

反正这里有一个如何在Moq

insightEmailService.Setup(mock => mock.FindAndIncrementEmailForAccount(It.IsAny<Account>())) 
        .Verifiable(); 
+0

嘲笑的方法一个例子,我不知道怎样添加另一个抽象这里是要减少复杂性。发送*的电子邮件已被抽象为已实现接口的类,我*已*使用接口。 IInsightEmailService是加载InsightEmails的存储库。我可以将SystemReplyEmailSpec推入通知程序,并且这会将相关性降低到5,但我没有看到胜利。为什么要把另一个类放到这个地方(即相同的东西)比使用已经存在的代码更好? – 2013-05-01 21:21:53