4

我有一个应用程序,其中问题域由高度相关的域对象表示。我已经将域拆分为几个聚合根对象,这有助于对模型施加顺序,但是为单元测试安排先决条件是艰巨的,因为创建这些聚合根的实例需要创建大量引用的支持对象。

我想编写可重复的、独立的单元测试来运行应用程序而不需要外部依赖项(理想情况下不需要编写大量代码)。

我认为这些是我的选择。有任何偏好或其他建议吗?

  1. 编写构建脚本来设置项目数据库并将已知数据插入其中,然后执行单元测试。这是我最不喜欢的选项,因为它引入了外部依赖项(因此不是真正的单元测试)以及更多潜在的失败。它也不会隔离正在测试的业务功能,因为故障可能位于数据访问代码中。

  2. 创建可重用的工厂,这些工厂创建具有已知状态的域对象,针对其运行单元测试。这会很好用,但意味着要编写大量样板代码,因此当/如果模型发生更改时需要进行大量更改。

  3. (当前方法)将我的聚合根对象的二进制序列化创建到与测试项目一起签入的文件中。单元测试将它们反序列化以进行测试。这样做的缺点是,如果底层类型发生变化,反序列化将失败,并且必须重新创建所有序列化文件。

  4. 接受它并编写一个自定义序列化程序,将图形序列化为 XML 文件,这些文件可以签入解决方案并在测试时反序列化。与 2 一样,这意味着要编写大量的前期样板代码,但维护更容易,因为如果模型发生更改,可以使用文本编辑器轻松编辑序列化状态。

  5. UR DOIN IT RONG。您的域对象具有如此高度的引用性这一事实是主要问题。简化它。

谢谢!

4

2 回答 2

3

编写构建脚本来设置项目数据库并将已知数据插入其中,然后执行单元测试。这是我最不喜欢的选项,因为它引入了外部依赖项(因此不是真正的单元测试)以及更多潜在的失败。它也不会隔离正在测试的业务功能,因为故障可能位于数据访问代码中。

集成不是单元”是小问题(特别是与“测试或不测试”相比),我不会担心。这种方法还有其他更严重的问题:

  • 编写脚本。您很可能最终会手工编写 SQL 代码,这需要大量的纪律,尤其是在模型复杂的情况下。错别字很痛苦,很难调试/检测问题,您也需要考虑 IDE/工具。
  • 当您的模型更改时,您将修复那些引发相同问题的 SQL 脚本 - 拼写错误、难以发现的错误等等,缺乏 IDE 支持。

总的来说,这种方法在可维护性方面是昂贵的

创建可重用的工厂,这些工厂创建具有已知状态的域对象,针对其运行单元测试。这会很好用,但意味着要编写大量样板代码,因此当/如果模型发生更改时需要进行大量更改。

体面的方法,您应该研究使此过程更容易的库(提示:AutoFixtureNBuilder)。

(当前方法)将我的聚合根对象的二进制序列化创建到与测试项目一起签入的文件中。单元测试将它们反序列化以进行测试。这样做的缺点是,如果底层类型发生变化,反序列化将失败,并且必须重新创建所有序列化文件。

与构建脚本一相同的问题 - 更改将是昂贵的。

接受它并编写一个自定义序列化程序,将图形序列化为 XML 文件,这些文件可以签入解决方案并在测试时反序列化。与 2 一样,这意味着要编写大量的前期样板代码,但维护更容易,因为如果模型发生更改,可以使用文本编辑器轻松编辑序列化状态。

这与您的第二个解决方案基本相同,但中间是 XML。为什么要添加额外的层?

UR DOIN IT RONG。您的域对象具有如此高度的引用性这一事实是主要问题。简化它。

不太可能。就其性质而言,域对象往往很复杂。

结论

There are no quick-and-dirty workarounds to such problem. Complex domain means there has to be some extra work done at some point. Serialization-based solutions (1, 3, 4), even though some may seem easy now, will only postpone said extra work to the moment when changes are introduced. In almost every case, I'd go with better flexibility and readiness for changes (which only second solution offers - if done properly).

于 2013-01-19T14:19:08.273 回答
0

The problem you are talking about is that data is scattered around in the domain-object-graph:

if you want to calculate the price for an invoice you need article-prices, tax-information, customer-specific dicounts, deliveriy specific shipping-consts, ... .

One strategy to handle this complexity is by seperating the logic to get these detail-values from the actual calculation.

The calculation is a internal method with many parameters and minimal dependency to other domainobjects. This can be easily tested because it does not depend on the object graph any more.

An other strategy is to move the complex calculation from the domain into a seperate servicelayer that depend on other service-interfaces. For testing these service-interfaces can be replaced by mocks.

于 2013-01-19T16:14:03.683 回答