0

I know it is recommended to have "single assert" in tests or single group of "When" and "Then" in BDD paradigm.

I was thinking whether it would be okay to relax this assumption, when testing an asynchronous API. Where request has to be first made, and then later it completes.

Something like this:

@Rule
public final Java6JUnitSoftAssertions softly = new Java6JUnitSoftAssertions();

@Test
public void setLessStrictCriterionGivenAllFetchesCompleted() {
    givenRepoWithCriterion(new MockCriterion(2));
    givenAllFetchesCompleted();

    // When I set a less strict criterion of ">= 1"
    final MockCriterion criterionMinValue1 = new MockCriterion(1);
    itemRepo.setCriteriaAndFetch(criterionMinValue1);

    // Then there is a fetch request in the queue, to fetch ">= 1"
    assertQueue(criterionMinValue1);
    // And there are loading items
    assertRepoItems(null, null, null);
    assertAll();

    // -------- Notice second group of When-Then starts here --------

    // When the fetch finishes
    fetcher.yieldFetch();

    // Then item list is 1 2 3
    assertRepoItems(1, 2, 3);
}

Note that there are two groups of When-Then.

The assertAll() is there to force asserting the first group of AssertJ soft assertions.

The fetches are normally done via HTTP in the real implementation, but, for the tests, there is a mocked fetcher and the finish of a fetch is emulated via fetcher.yieldFetch();

Would you consider that overall structure to be a good way to write such tests?

What other/better ways might be there?

KarolDepka
  • 8,318
  • 10
  • 45
  • 58
  • 1
    Using mock objects to mimic user behaviour seems not very BDD. Is BDD really a 'thing' here or are you more concerned about high-level integration tests which depend on asynchronous behaviours? – sisyphus Jan 04 '17 at 01:29
  • Thanks for your comment. The truth is, that I got a review, for a previous version, saying "use given/when/then" and "one assert per test". So I'm trying to adjust to that. The reviewer is not readily available to answer my questions, so I'm improvising somewhat. Instead of Given/When/Then, I could also use Arrange/Act/Assert, I guess. And, lastly: this is a unit test, not integration test. – KarolDepka Jan 04 '17 at 03:03
  • @sisyphus: Btw, the mock is not emulating **user** behaviour, but rather emulating fetching via HTTP. – KarolDepka Jan 04 '17 at 03:05
  • 1
    I think your approach is OK as long as you have a separate test for the first part of this "workflow". But in that case this test should not repeat the assertions of that other test. – Timothy Truckle Jan 04 '17 at 07:16
  • Thanks for your comment. Upvoted. Could you write down the benefits of having this as two separate tests? On the other hand, a cost seems to be some amount of duplication and multiplying the number of tests ~2-fold... – KarolDepka Jan 04 '17 at 15:29

0 Answers0