TDD - 顶级功能有太多的模拟.我是否应该费心去测试呢?

dfe*_*aro 7 tdd unit-testing mocking

我有一个带有Web前端,WCF Windows服务后端的.NET应用程序.应用程序非常简单 - 需要一些用户输入,将其发送到服务.该服务执行此操作 - 获取输入(Excel电子表格),提取数据项,检查SQL DB以确保项目尚不存在 - 如果它们不存在,我们向第三方数据供应商发出实时请求并检索结果,将它们插入数据库.它沿途做了一些记录.

我有一个Job类,有一个公共ctor和公共Run()方法.ctor接受所有参数,Run()方法执行上述所有逻辑.每个逻辑功能部分被拆分为一个单独的类 - IParser执行文件解析,IConnection执行与数据供应商的交互,IDataAccess执行数据访问等.Job类具有这些接口的私有实例,并使用DI构建默认情况下实际实现,但允许类用户注入任何接口.

在实际代码中,我使用默认的ctor.在我对Run()方法的单元测试中,我使用通过NMock2.0创建的所有模拟对象.此Run()方法本质上是此应用程序的"顶级"功能.

现在这是我的问题/问题:这个Run()方法的单元测试很疯狂.我有三个模拟对象,我发送到ctor,每个模拟对象设置自己的期望.最后,我验证.我有一些Run方法可以采用的不同流程,每个流程都有自己的测试 - 它可以找到数据库中的所有内容,而不是向供应商发出请求......或者可以抛出异常并且作业状态可以被设置为'失败'...或者我们可以得到我们没有数据并且需要发出供应商请求的情况(因此需要进行所有这些函数调用).

现在 - 在你对我大喊并说'你的Run()方法过于复杂之前!' - 这个Run方法只有50行代码!(它确实调用了一些私有函数;但整个类只有160行).由于所有"真实"逻辑都是在此类声明的接口中完成的.但是,这个函数最大的单元测试是80行代码,有13个调用Expect.BLAH().. _

这使得重新考虑了巨大的痛苦.如果我想改变这个Run()方法,我必须编辑我的三个单元测试并添加/删除/更新Expect()调用.当我需要重构时,我最终花费更多时间创建模拟调用,而不是实际编写新代码.在这个功能上做真正的TDD使得它变得更加困难,如果不是不可能的话.它让我觉得它根本不值得对这个顶级函数进行单元测试,因为实际上这个类没有做太多逻辑,它只是将数据传递给它的复合对象(它们都是完全单元测试的,不需要嘲讽).

那么 - 我是否应该费心去测试这个高级功能呢?这样做我获得了什么?或者我在这里完全滥用mock/stub对象?也许我应该废弃这个类的单元测试,而只是进行自动化集成测试,它使用对象的实际实现和Asserts()对SQL查询来确保存在正确的最终状态数据?我在这里错过了什么?

编辑:这是代码 - 第一个函数是实际的Run()方法 - 然后我的五个测试测试所有五个可能的代码路径.我因为NDA原因改变了一些,但一般的概念仍然存在.你对我如何测试这个功能有什么看错了,有什么改变的建议让它变得更好?谢谢.

Wal*_*ter 5

我想我的建议与这里发布的大部分内容相呼应。

听起来好像您的 Run 方法需要进一步分解。如果它的设计迫使您进行比实际更复杂的测试,则说明有问题。请记住,我们正在讨论的是 TDD,因此您的测试应该决定例程的设计。如果这意味着测试私有函数,那就这样吧。任何技术哲学或方法都不应该过于僵化,以至于你无法做感觉正确的事情。

此外,我同意其他一些海报,即您的测试应该分解为更小的部分。问问自己,如果您第一次编写这个应用程序并且您的 Run 函数还不存在,您的测试会是什么样子?该答复可能不是您当前的答复(否则您不会问这个问题)。:)

您确实拥有的一个好处是类中没有太多代码,因此重构它应该不会很痛苦。

编辑

刚刚看到您发布了代码并有一些想法(没有特定的顺序)。

  1. SyncLock 块内的代码(IMO)太多了。一般规则是使 SyncLock 内的代码保持最少。必须锁起来吗?
  2. 开始将代码分解为可以独立测试的函数。示例:ForLoop 从列表(字符串)中删除 ID(如果它们存在于数据库中)。有些人可能会认为 m_dao.BeginJob 调用应该在某种可以测试的 GetID 函数中。
  3. m_dao 过程中的任何一个都可以变成可以自行测试的函数吗?我假设 m_dao 类在某处有它自己的测试,但通过查看代码,情况似乎并非如此。它们应该与 m_Parser 类中的功能一起。这将减轻运行测试的一些负担。

如果这是我的代码,我的目标是让代码到达 Run 中的所有单独过程调用都单独测试的位置,并且 Run 测试只是测试最终结果。给定输入 A、B、C:期望结果 X。给定输入 E、F、G:期望 Y。Run 如何到达 X 或 Y 的细节已经在其他过程的测试中进行了测试。

这些只是我最初的想法。我确信人们可以采取多种不同的方法。