In the Arrange-Act-Assert test style, is it OK to move the Act into a beforeEach/setUp block?

1.2k views Asked by At

When unit testing the result and/or side effects from a single logical action, how do you keep the code DRY? Take the following example written in 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. */
});

Notice the repeated Act with the calls to frobnicate(foo). With a unit testing framework that allows for nested describe contexts (such as Jasmine), it seems very natural to refactor the tests along the lines of:

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. */
});

Is this style in any way contradictory to the AAA testing style? Does refactoring the code this way invite other problems?

2

There are 2 answers

0
tddmonkey On BEST ANSWER

Not only is this not-contradictory to Arrange-Act-Assert but I would insist you do do it this way. Duplication in tests is one of the major maintenance problems and removal should be done as much as possible.

The biggest question to ask on duplication is "what would happen if this changes?", if you have to change it in multiple places, refactor.

0
Dave Schweisguth On

No, it's not OK. Yes, putting the Act in a setup step does invite problems, or suggests that you might already be headed down a problematic path.

People usually want to do that because they believe that they are only allowed one assertion per test. They find that testing a given combination of Arrange and Act needs more than one assertion, so they write a test for each assertion. Now the Arrange-Act combination is duplicated, so they move it into a setup step. But now they have new problems:

  • Tests written in this way often require a lot of syntax to say what could have been said much more simply by putting all of the assertions in the same test.

  • If Arrange and/or Act take any time to run, there are now many slow tests instead of just one.

  • All of the test frameworks I've used call their setup steps "before", "setUp", etc., no doubt because their authors were thinking of using those steps for Arrange, not Act. If you're trying to write tests that read well, the contradictory language is jarring.

So, I generally write one test for each distinct Arrange-Act pair and use as many assertions as I need in that test.