TDD,DDD和封装

时间:2009-07-17 20:53:11

标签: c# tdd domain-driven-design encapsulation getter

经过几年跟随我工作地点“建筑师”传下来的不良做法并认为必须有更好的方法,我最近一直在阅读TDD和DDD,我认为原则和做法非常适合我们编写的软件的复杂性。

但是,我见过的许多TDD示例都在域对象上调用一个方法,然后测试对象的属性以确保行为正确执行。

另一方面,业内几位受人尊敬的人(Greg Young最着名的是关于CQRS的讨论)主张通过删除所有“getters”来完全封装每个域对象。

因此,我的问题是:如果禁止检索域状态,那么如何测试域对象的功能呢?

我相信我错过了一些基本的东西,所以请随时称我为白痴并启发我 - 任何指导都将不胜感激。

8 个答案:

答案 0 :(得分:17)

您所描述的是状态验证,其中您断言域对象的状态。 TDD的一个分支被称为行为验证,它利用了Mock对象。

行为验证允许您指定应调用哪些方法,以及是否需要调用哪些方法。

请参阅Martin Fowler的这篇文章了解更多详情:Mocks Aren't Stubs

答案 1 :(得分:9)

好的,这个答案已经晚了一年; - )

但是当你想测试CQRS模型时,可以对被触发的域事件进行断言,而不是对实体状态进行断言。

e.g。 如果你想测试是否调用:customer.Rename(“Foo”)会导致正确的行为。

而不是测试customer.Name是否等于“foo”,而是测试在待处理事件存储中是否存在值为“Foo”的待处理CustomerRename事件。 (根据实施情况,在您的uow或实体事件列表中)

答案 2 :(得分:4)

如果你真的要去禁止检索状态,那么你将被限制在行为测试中,可能是通过一个模拟框架,如TypeMock,它有能力跟踪你的对象的行为。如果你能够做纯BDD,那么理论上你可以通过它的行为方式断言你整个系统的正确性。

在实践中,我发现BDD在很多情况下比仅有状态测试更脆弱。虽然有些人可能会要求某种理论,但它只适用于你的工作。基于状态的测试仍占我们编写的所有单元测试的90%,我们对团队中的BDD了如指掌。

做最适合你的事情。

答案 3 :(得分:2)

一些事情。

首先,当您执行TDD之类的操作以使您的代码可测试时,您最终会使用较小的类。如果你有一个有很多私有属性的类你无法检查,那么它很有可能被分成多个类并且更容易测试。

其次,oldschool OO架构试图通过使用语言保护来防止事物被访问,从而使软件安全。 TDD体系结构通过编写验证代码实际功能的测试来使软件更加健壮,不太重视使用语言结构来确保程序不执行的操作。

最后,检查属性并不是验证代码执行操作的唯一方法。 xUnit Design Patterns一书记录了其他方法:http://xunitpatterns.com/Result%20Verification%20Patterns.html

答案 4 :(得分:2)

我调用系统的公共输入方法(即我将输入数据推送到系统中),然后我得到(并断言)系统的输出。我没有测试系统的内部状态,而是测试其公开/可见行为:Should one test internal implementation, or only test public behaviour?

答案 5 :(得分:2)

你提到的是状态测试。还有行为测试。用于此的技术是依赖注入,控制反转和模拟:

您的类的所有副作用都是作为其“依赖项”的方法调用实现的 - 即从外部提供的对象,通常是在构造函数中。然后,在您的单元测试中,您提供虚假对象而不是真实对象。假对象可以记住它的'某个方法是否被调用,这就是你在测试中断言的内容。

存在许多模拟框架,它们通过动态生成实现给定接口的类来自动创建模拟对象。最受欢迎的是Rhino.Mocks和Moq。

答案 6 :(得分:2)

嘿贾斯汀,和你一样,我最近考虑为了单元测试而将getter添加到我的只写域对象中,但现在我确信我错了。假设你首先考虑了一个只写域的想法,那么如果你有吸气剂,你就会遇到麻烦。只写域原则要求您从域对象触发事件,或从域对象写入的投影中读取,或者类似的东西。一旦暴露了getter,你就会开始暴露对象的“形状”,正如Greg Young所说,“Domain对象有行为,而不是Shape”。

话虽如此,我正在努力解决同样的问题......你如何对只写域对象进行单元测试?这是我目前的计划:我正在考虑让我的域对象触发一个域事件,说“这些属性发生了变化”,在我的单元测试中,我会在发送“EditCommand”之前注册它。查看Udi Dahan关于域名活动here的帖子,并查看what Eric Evans says about Domain Events

答案 7 :(得分:1)

我一直想知道同样的事情,直到我最后偶然发现了以下文件。我发现它们是执行行为验证的绝佳引子,尤其是第一个为我提供了几个“aha时刻”的引物:

  1. Using Mocks and Tests to Design Role-Based Objects
  2. Mock Roles, Not Objects