单元测试复杂的对象图

时间:2013-10-09 04:37:25

标签: asp.net-mvc unit-testing repository-pattern service-layer

想象一下中等复杂度的asp.net mvc应用程序,它将存储库模式与服务层结合使用。现在假设我们有一些具有广泛依赖性的行为。举一个人为的例子:CustomerController需要显示符合以下所有条件的客户:

  • 客户的帐单或送货地址在佛罗里达州
  • 客户在VIP俱乐部(使用ClubMembershipService)
  • 客户至少有一个以前的订单
  • 客户拥有至少一辆型号为2005年或更新的汽车
  • 汽车有一个被召回的部分
  • 等等,还有一些一对一或第三方API调用

此范围的每项测试都需要大量的种子/模拟数据。我的下一个测试可能需要一组相似但却截然不同的数据。假设在控制器级别进行的任何测试都需要注入6个服务,然后将8个存储库注入这些服务。

如何让我的测试可管理?如何在深度对象图中导航并确保模拟(或具体)存储库提供有效,一致的数据,而每次测试中没有30行设置代码?

e.g。如果这是使用测试数据库的纯集成测试,我可能需要以下内容:

  • 一些客户记录
  • 一些地址记录;一些客户有多个地址记录;送货地址在佛罗里达州的;一个帐单地址在佛罗里达州的人
  • 几个订单
  • 一些“CustomerCar”记录;其中一辆车应该有2005年或更新的车型
  • 一些“CarPartRecall”记录;其中一些将与CustomerCar记录的品牌,型号和年份相匹配
  • 以及其他标准/逻辑

我理解将这些条件作为属性附加到Customer对象可能是有意义的,例如customer.IsInVipClub。我对那些不能转换为简单属性的复杂情况更感兴趣,因为它们跨越多个聚合边界。例如customer.Owns2005OrNewerCarWithRecalledParts是我通常不会写的属性。

建议使用AutoFixture。它看起来像是一个模拟框架和一个夹具工厂之间的交叉(就像在factoryGirl for rails中一样)。我认为通过自动提供一些属性值(例如customer.firstName)可以使初始化代码更简洁,但感觉这是一个相对较小的增益。我有兴趣听听任何人使用AutoFixture的经历。

1 个答案:

答案 0 :(得分:1)

您的问题看起来像简单查询,测试它没有任何价值。并非所有事情都需要联合测试。

如果你真的想测试它,你可以做集成测试。设置一个测试数据库,最好是在内存中,插入您的虚拟数据,运行查询断言结果并删除虚拟数据。每次测试都重复。

对于第三方API调用,除了嘲笑它们之外别无他法。

这仍然是很多工作,但有些测试更难做,需要更多的工作才能构建。

请记住,单元测试需要快速运行。如果他们开始花费更长的时间来运行,他们的运行频率就会降低。另一方面,集成测试可能会不时运行,并且可能需要更多时间。