2008-12-19 102 views
1

我是单元测试新手,目前在找到一种体面的方法来测试包含分支的方法时遇到了问题。包含条件条件的单元测试方法的最佳实践

我创建了一个小的演示方法,我希望可以用来解释这个问题。

public void ExportAccounts() 
{ 
    int emptyAccounts = 0; 
    int nonEmptyAccounts = 0; 
    int errorous = 0; 
    string outputPath = this.GetOutputPath(); 
    Account[] accounts = this.MyWebserviceAdapter.GetAccounts(); 
    foreach(Account account in accounts) 
    { 
     try 
     { 
      if(account.Amount > 0) 
      { 
       this.ExportNonEmpty(outputPath, account); 
       nonEmptyAccounts++; 
      } else { 
       this.ExportEmptyAccount(outputPath, account); 
       emptyAccounts++; 
      } 
     } catch(Exception e) { 
      logger.error(e); 
      errorous++; 
     } 
    } 
    logger.debug(string.Format("{0} empty/{1} non empty/{2} errorous", emptyAccounts, nonEmptyAccounts, errorous)); 
} 

我可以模拟MyWebserviceAdapter以返回预定义的帐户列表。我是否应该在同一个测试中输入空的和非空的账户清单,还是应该单独进行测试?

另外我的ExportNonEmpty()和ExportEmpty()方法是私有的,但是将文件写入文件系统。我应该提供一个模拟FileProvider,以便文件系统不被触及?

我应该公开ExportNonEmpty()和ExportEmpty()以便能够分别测试这些吗?这些方法还包含一些if-then-else语句,并可以引发异常和异常。

我发现如果我为每个代码路径创建一个测试我有从一个测试复制代码到另一个 - 生成嘲笑等..不是有点奇怪?

我应该公开计数器变量作为出变量,以便能够在调用方法后验证它们吗?

this.GetOUtputPath()通过静态的ConfigurationManager从配置文件中获取值。我应该a)通过为testt下的类创建一个部分模拟并覆盖GetOutputPath方法或者b)创建我自己的可以被嘲笑的配置适配器来模拟这一点?

我正在使用nunit和Rhino Mocks。

回答

1

我会用几个测试向量来测试它:全空,全非空,以及以空和非空开始和结束的混合开始和结束。

至于验证结果:揭露和测试计数器会给出一个“白盒”测试,在测试中知道对象的内部状态,这会给出一个更彻底的测试,但是使其更难稍后更改实施。 (如果更改实现,即使效果相同,测试也可能失败)。

我的偏好通常是测试«黑匣子»,只测试操作的外部可观察到的后果。然后,如果公开的功能仍然相同,则可以更改内部结构和回归测试。但是,这可能需要更多的模拟编码。

对于java,有相当多的库可以帮助您构建模拟对象,我不知道.net,但我会假设情况相同。

+0

那么你会为每个测试向量有一个单独的测试方法吗?这样做会导致许多嘲笑必须复制到我所推测的每种测试方法中。你可以评论你将如何做到这一点? – Fadeproof 2008-12-19 13:36:06

1

针对每种情况的单独测试。我假设你相信foreach遍历一个包含两者的循环。我会。假设你正在测试你在其他地方嘲笑的方法,以确保它在出现时正确地返回两种类型的帐户。

除了复制代码之外,还可以通过将常用代码提取到测试类中的方法甚至TestHelper类中来重构代码。如果需要使它们参数化,使它们通常可用。

您应该可以通过为测试中的类添加访问器来测试您的私有方法。如果在私有方法中使用“创建单元测试”右键单击菜单项,或者将私有方法作为一个单独添加以创建单元测试以添加整个课程,则会自动添加一个。为了测试ExportAccounts,只需使用您知道的数据,并且不会抛出异常,以便您可以测试直线逻辑和异常处理。

我不会公开方法变量。在方法之外不需要它们。然而,你应该模拟记录器以确保它被调用期望的参数。

创建ConfigurationAdapter(或Wrapper)并将其注入到类中以除去对静态类的依赖关系。嘲笑适配器或提供一个假实现,您的选择。无论如何,去除依赖是一种很好的模式。我不喜欢在测试中嘲笑或残缺任何东西。

编辑:有关单位测试基本的阅读,我会建议Pragmatic Unit Testing(C#版本)和Code Complete单元测试的章节。你可能也想拿起Test Driven Development in .Net,但其他人更一般。

+0

您提到提取通用代码,我同意这将是一个好主意 - 但问题是您注入的模拟不能提取,因为我在每个测试方法中设置预期的调用,因此如果测试不同条件采用不同的测试方法。 – Fadeproof 2008-12-19 13:51:47