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

时间:2013-01-19 13:58:16

标签: c# unit-testing testing serialization tdd

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

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

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

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

  2. 创建可重用的工厂,创建具有已知状态的域对象,运行单元测试。这样可以很好地工作,但意味着需要编写大量的样板代码,因此在模型更改时会有很多变化。

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

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

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

  6. 谢谢!

2 个答案:

答案 0 :(得分:3)

  

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

“integration not unit”是次要问题(特别是与“test或not test”相比时),我不担心。这种方法还有其他更严重的问题:

  • 编写脚本。你最有可能最终手工编写SQL,这需要很多纪律,特别是当模型很复杂时。错别字很难调试/检测问题,你也需要考虑IDE /工具。
  • 当您的模型发生变化时,您将修复那些引发相同问题的SQL脚本 - 拼写错误,难以发现错误等等,缺乏IDE支持。

总体而言,这种方法在可维护性方面非常昂贵

  

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

体面的方法,您应该调查使这个过程更容易的库(提示:AutoFixtureNBuilder)。

  

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

与build-scripts相同的问题之一 - 更改将是昂贵的。

  

将其解压缩并编写一个自定义序列化程序,将图表序列化为XML文件,这些文件可以在检查时签入并反序列化。与2类似,这意味着需要编写大量的前期样板代码,但维护更容易,因为如果模型发生变化,可以使用文本编辑器轻松编辑序列化状态。

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

  UR正在努力。您的域对象如此高度引用这一事实是主要问题。简化它。

相当不可能。根据他们的性质域对象,它们往往很复杂。

结论

此类问题没有快速和肮脏的解决方法。复杂域意味着必须在某些时候完成一些额外的工作。 基于序列化的解决方案(1,3,4),即使现在看起来有些简单,但只会将所述额外工作推迟到引入更改的那一刻。在几乎所有情况下,我都会更好地灵活性准备好进行更改(只有第二种解决方案才能提供 - 如果操作正确的话)。

答案 1 :(得分:0)

您所谈论的问题是数据分散在域对象图中:

如果您想计算发票的价格,您需要物品价格,税务信息,客户特定的数字,交付特定的运输协议......,

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

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

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