【问题标题】:How do I unit test code that uses a Fluent interface?如何对使用 Fluent 接口的代码进行单元测试?
【发布时间】:2009-08-17 22:06:18
【问题描述】:

我通过方法链创建了一些小的流畅接口。他们通常调用一些从 web 服务/数据库中获取数据的存储库。

我应该如何使用 fluent 接口的单元测试方法?

Public IEnumberable<Computer> FindComputers(string serialNumber)
{
      return Computers.FindBySerialNumber("YBCX00900")
         .AttachConfiguration()
         .EnsureAllComputersHaveConfiguration();
}

我可以对 fluent interface 的各个组件进行单元测试,但是如果我想对上面的 FindComputers 方法进行单元测试,我应该怎么做?

  1. 使用fluent接口的具体实现,写 对 Repository 类的期望
  2. 模拟流畅的界面本身并对其设定期望
  3. 只测试 fluent 接口本身,而不是 FindComputers() 方法

我想找到一种易于维护的方法。

【问题讨论】:

    标签: c# .net unit-testing fluent-interface


    【解决方案1】:

    我认为 FI 做的比它需要的要多。我假设您使用计算机作为数据映射器,并且还使用它来构建查询。根据您显示的内容,查询是由此建立的:

    rule 1: find configured computer with serial number = "whatever" and has-config = true.
    rule 2: find not-config computer with serial number = "whatever and has-config = true.
    rule 3: find configured computer with serial number = "whatever" and has-config = false.
    rule 4: find not-config computer with serial number = "whatever" and has-config = false.
    rule 5: find all computer with serial number = "whatever" and has-config = true.
    rule 6: find all computer with serial number = "whatever" and has-config = false.
    

    等等……

    现在,其中一些可以实施的规则似乎是不正确的。规则 2 和规则 3 似乎有交叉的目的。规则 5 和规则 6 做什么?这样做对吗?

    因为您实现了一个破坏 SRP 的对象。第一步是将查询构建器从数据映射器中分离出来。构建您的 FI 查询对象,然后将其传递给映射器。

    现在您可以测试FindComputers,确保将 FI 查询对象发送到数据映射器。因为您现在可以构建一个 FI 查询对象,所以您可以对其进行测试。并且您可以测试数据映射器是否使用查询对象。

    如果将来您想按位置查找计算机,该怎么办。如果您保留与您编写的代码相同的代码,则必须添加一个方法FindByLocation,并且在您知道它之前,您已经拥有了一个上帝对象。臭!

    【讨论】:

    • 谢谢,你说得对,这个例子考虑得不好,我已经将 FI 分解为一个用于查询,一个用于对返回的数据执行操作。我发现单独对 FI 进行单元测试是最简单的,然后对使用 FI 和具体实现的单元测试方法进行单元测试。只是测试是否返回了所需的结果。试图模拟 FI 只会让测试变得过于脆弱。
    【解决方案2】:

    您可以模拟您的存储库吗?虽然有些人会提倡一种更纯粹的方法,您必须隔离一个类的一个方法,但这将是测试 FindComputers 和流式接口如何协同工作的一种不错的方法。而且它可能更简单,具体取决于存储库访问层的样子。

    【讨论】:

      【解决方案3】:

      我会做 2+3。假设流利的接口是真正的接口,它们应该相对容易模拟。只要意识到调用链中的每一步都应该返回一个新的模拟对象,这反过来又期待链中的下一个调用。

      您仍然应该直接测试 fluent 接口,模拟它们下面的存储库层。

      【讨论】:

      • 感谢您的输入,我想过模拟流畅的界面本身,但编写测试似乎有点奇怪...... Expect(x => x.FindBySerialNumber(null)).Return(nextMock ) Expect(x => x.AttachConfiguration()).Return(nextMock) 当所有它测试的是调用是实际进行时。在 mock 对象中重新创建整个 fluent 接口需要做很多工作,只是为了测试在被测方法中已经清楚写入的内容。
      • 我不熟悉单元测试覆盖率,有时也有同样的疑虑。虽然通过检查很容易审查代码,但这仍然是人工审查。当您不再考虑此类时,添加测试覆盖有助于保护您。这也可能表明 fluent 接口比它需要的更复杂 - 如果接口更专注于您需要的测试,那么编写起来也会更简单。
      猜你喜欢
      • 2011-03-08
      • 1970-01-01
      • 2012-02-26
      • 2012-02-03
      • 1970-01-01
      • 2021-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多