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) 创建我自己的可以模拟的 ConfigurationAdapter?

我正在使用 nunit 和 Rhino Mocks。

4

2 回答 2

1

我将使用几个测试向量对此进行测试:全空、全非空以及以空和非空开始和结束的混合。

至于验证结果:暴露和测试计数器将给出一个“白盒”测试,该测试知道对象的内部状态,这给出了更彻底的测试,但使得以后更改实现更加困难. (如果您更改实现,即使效果相同,测试也可能会失败)。

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

对于java,有很多库可以帮助您构建模拟对象,我不了解.net,但我认为情况也是如此。

于 2008-12-19T13:33:28.637 回答
1

对每个条件进行单独的测试。我假设您相信 foreach 会遍历包含两者的循环。我会。大概您正在测试您在其他地方模拟的方法,以确保它在存在时正确返回两种类型的帐户。

您可以通过将通用代码提取到测试类的方法中,甚至提取到 TestHelper 类中来重构,而不是复制代码。如果需要,请对它们进行参数化以使它们普遍可用。

您应该能够通过为被测类添加访问器来测试您的私有方法。如果您在私有方法中使用“创建单元测试”右键单击菜单项,或者在为整个类添加时简单地将私有方法添加为一个以创建单元测试,则会自动添加一个。对于测试 ExportAccounts,只需使用您知道会引发和不会引发异常的数据,以便您可以测试直线逻辑和异常处理。

我不会公开方法变量。在方法之外不需要它们。但是,您应该模拟记录器以确保使用预期的参数调用它。

创建 ConfigurationAdapter(或 Wrapper)并将其注入您的类以消除对静态类的依赖。模拟适配器或提供虚假的实现,由您选择。无论如何,删除依赖项是一个很好的模式。我不喜欢在被测类中模拟或存根任何东西。

编辑:对于单元测试的基本阅读,我会推荐实用单元测试(C# 版本)和代码完成中的单元测试一章。您可能还想学习 .Net 中的测试驱动开发,但其他更通用。

于 2008-12-19T13:35:03.967 回答