【问题标题】:Specification Pattern Unit Tests [closed]规范模式单元测试
【发布时间】:2010-02-06 21:42:17
【问题描述】:

我们最近采用了用于验证域对象的规范模式,现在想要对我们的域对象进行单元测试以提高代码质量。

我发现的一个问题是如何最好地对下面示例中显示的验证功能进行单元测试。规范命中数据库,所以我希望能够模拟它,但由于它是在线实例化的,我不能这样做。我可以处理接口,但这会增加代码的复杂性,因为我们可能有很多规范,我们最终会有很多接口(请记住,我们正在引入单元测试,不想给任何人拍摄它的借口下)。

在这种情况下,我们如何最好地解决在我们的领域对象中对规范模式进行单元测试的问题?

...
public void Validate()
{
    if(DuplicateUsername())
    { throw new ValidationException(); }
}

public bool DuplicateUsername()
{
    var spec = new DuplicateUsernameSpecification();
    return spec.IsSatisfiedBy(this);
}

【问题讨论】:

    标签: c# unit-testing design-patterns agile domain-driven-design


    【解决方案1】:

    可以通过创建核心方法virtualSeams 更温和地引入应用程序。这意味着您可以使用 Extract and Override 技术进行单元测试。

    在新开发开发中,我发现这种技术不是最理想的,因为有更好的替代方案可用,但它是改进现有代码可测试性的好方法。

    作为一个例子,你写你的规范命中数据库。在该实现中,您可以将规范的该部分提取到 Factory Method,然后您可以在单元测试中覆盖它。

    总的来说,Working Effectively with Legacy Code 这本书提供了很多关于如何使代码可测试的宝贵指导。

    【讨论】:

    • 感谢您的反馈 Mark,我同意您所说的一切,但希望能找到一个体面的解决方案。在测试项目中继承类和覆盖方法有一些不好的地方,我认为如果我们首先提出一个体面的设计,我们可以避免这将是开销,这是我希望的离开这篇文章。
    • @Burt:那我可能误解了你的问题。 “体面”的设计围绕着 SOLID。特别是开放/封闭原则对于可测试性非常重要。这又涉及到 DI,这意味着很多接口和抽象工厂,我读了你的问题,大意是你现在真的负担不起这笔税。
    • 我不想太过分,但看起来界面将是实现我想要的最佳方式。
    • 使用接口绝对是最好的长期策略,因为它更符合“优先组合优于继承”的理念。
    【解决方案2】:

    如果您不想对工厂进行构造函数注入,并使规范可模拟...您是否考虑过 TypeMock?它对于处理这类事情非常强大。你可以告诉它模拟下一个要创建的 X 类型的对象,它可以模拟任何东西,不需要虚拟等。

    【讨论】:

      【解决方案3】:

      您可以将getDuplicateUsernameSpecification() 提取到它自己的公共方法中,然后为您的测试子类化并覆盖它。

      【讨论】:

      • 这是个好主意,我们正在考虑覆盖域对象并覆盖 DuplicateUsername 方法,但它不适合我。
      【解决方案4】:

      如果您使用 IoC,那么您可以解析 DuplicateUsernameSpecification 并在测试模型中使用最后一个

      编辑:想法是用工厂方法替换直接构造函数调用。像这样的:

      public bool DuplicateUsername()
      {
          var spec = MyIocContainer.Resolve<DuplicateUsernameSpecification>();
          return spec.IsSatisfiedBy(this);
      }
      

      【讨论】:

      • 使用 IoC 容器作为服务定位器通常不是最佳实践。你最好使用构造函数注入。你仍然可以使用容器,但它只需要在你的应用程序的一个地方出现(或耦合到)。
      • 我想过这个并尝试实现它,我可以使用模拟框架(即 MOQ)模拟一个没有接口的具体类吗?
      • 我认为不可能模拟一个不是虚拟的方法,所以如果可以使用 ISpecification { bool IsSatisfiedBy(T target); 这样的接口进行泛化验证} 可以工作。
      • 2TrueWill:实现可以是服务定位器或任何类型的 DI,其想法仍然是替换难以模拟的直接构造函数调用
      猜你喜欢
      • 2012-02-06
      • 1970-01-01
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-22
      • 1970-01-01
      • 2020-08-10
      相关资源
      最近更新 更多