用于安排单元测试的序列化对象图

本文关键字:序列化 对象图 单元测试 用于 | 更新日期: 2023-09-27 17:54:21

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

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

我想这些是我的选择。有什么偏好或其他建议吗?

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

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

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

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

  5. 你做错了。您的域对象具有如此高的引用性这一事实是主要问题。简化它。

谢谢!

用于安排单元测试的序列化对象图

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

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

  • 编写脚本。您很可能最终会手工编写SQL代码,这需要很多纪律,尤其是在模型复杂的情况下。打字错误是痛苦的,很难调试/检测问题,你需要考虑IDE/工具也。
  • 当您的模型更改时,您将修复那些SQL脚本,这些脚本会引起相同的问题-拼写错误,难以发现错误等,缺乏IDE支持。
总的来说,就可维护性而言,是昂贵的

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

不错的方法,你应该研究使这个过程更容易的库(提示:AutoFixtureNBuilder)。

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

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

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

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

你做错了。您的域对象具有如此高的引用性这一事实是主要问题。简化它。

,而不太可能的。就其本质而言,它们往往是复杂的。

结论

对于这样的问题,没有快捷的解决方法。复域意味着在某一点上必须做一些额外的工作。基于序列化的解决方案(1,3,4),尽管有些现在看起来很简单,但只会将这些额外的工作推迟到引入更改的那一刻。在几乎所有情况下,我都会使用更好的灵活性对更改的准备程度(只有第二个解决方案提供-如果做得好)。

你所说的问题是数据分散在域-对象-图中:

如果您想计算发票的价格,您需要物品价格、税务信息、客户特定折扣、交付特定运费,... .

处理这种复杂性的一种策略是将获取这些细节值的逻辑与实际计算分离。

计算是一个内部方法,有许多参数和最小的依赖于其他域对象。这可以很容易地测试,因为它不再依赖于对象图。

另一种策略是将复杂的计算从域移到依赖于其他服务接口的独立服务层。为了测试这些服务接口,可以用模拟代替。