2

在对单个逻辑操作的结果和/或副作用进行单元测试时,如何保持代码 DRY?以 Jasmine 编写的以下示例为例:

describe("frobnicate", function () {
  var foo;

  beforeEach(function () {
    foo = getFoo();
  });

  it("causes side-effect 1", function () {
    frobnicate(foo);

    expect(sideEffect1).toEqual('you did it');
  });

  it("causes side-effect 2", function () {
    frobnicate(foo);

    expect(sideEffect2).toHaveBeenCalled();
  });

  /* side effect 3, 4, etc. */
});

请注意重复的 Act 以及对 的调用frobnicate(foo)。使用允许嵌套描述上下文(例如 Jasmine)的单元测试框架,按照以下方式重构测试似乎很自然:

describe("frobnicate", function () {
  beforeEach(function () {
    var foo = getFoo();

    frobnicate(foo);
  });

  it("causes side-effect 1", function () {
    expect(sideEffect1).toEqual('you did it');
  });

  it("causes side-effect 2", function () {
    expect(sideEffect2).toHaveBeenCalled();
  });

  /* test side effect 3, 4, etc. */
});

这种风格与 AAA 测试风格有任何矛盾吗?以这种方式重构代码会引发其他问题吗?

4

2 回答 2

3

这不仅与 Arrange-Act-Assert 不矛盾,而且我会坚持你这样做。测试中的重复是主要的维护问题之一,应尽可能多地删除。

关于重复要问的最大问题是“如果改变会发生什么?”,如果你必须在多个地方改变它,重构。

于 2014-12-22T15:52:08.153 回答
1

不,这不好。是的,将法案放在设置步骤中确实会引发问题,或者表明您可能已经走上了一条有问题的道路。

人们通常想要这样做,因为他们认为每次测试只允许他们一个断言。他们发现测试 Arrange 和 Act 的给定组合需要多个断言,因此他们为每个断言编写一个测试。现在 Arrange-Act 组合被复制了,因此他们将其移至设置步骤。但现在他们有新的问题:

  • 以这种方式编写的测试通常需要大量语法来说明通过将所有断言放在同一个测试中可以更简单地表达的内容。

  • 如果 Arrange 和/或 Act 需要任何时间来运行,现在会有许多慢速测试,而不仅仅是一个。

  • 我使用的所有测试框架都将它们的设置步骤称为“之前”、“设置”等,这无疑是因为它们的作者正在考虑将这些步骤用于 Arrange,而不是 Act。如果您尝试编写可读性好的测试,那么矛盾的语言会很刺耳。

因此,我通常为每个不同的排列-动作对编写一个测试,并在该测试中使用尽可能多的断言。

于 2015-08-08T15:22:43.353 回答