orlade
orlade

Reputation: 2090

Unit testing with generated inputs and expected outputs

I'm writing some simple unit tests for a method which acts like a database query: it returns a list of results that can be customised using a limit (max of n results) and a page (the p'th set of n results). I'd like to test a few cases, such as:

I need to mock the results (effectively names) that are returned, so I'm just generating them with a counter to make a list of "Name #1", "Name #2", etc. for as many as I need. Each test looks (roughly) like:

public void testGetMockCandidatesLimited() throws Exception {
    int numResults = 4;
    setupMock(numResults);
    results = queryFunction(...);

    // Check that the expected number of results was returned
    assertEquals(numResults, results.size());
    // Check that the results are correct and in order
    for (int i = 0; i < numResults; i++) {
        assertEquals(result.get(i).getName(), "Name #" + (i + 1));
    }
}

My question is: is it okay to 'generate' the expected answers in this way? This is a trivial example, but the next step was to write a test to write a test to get the second page of two results each, and I had:

    final int TEST_LIMIT = 2, TEST_PAGE = 1;
    // Check that the expected number of results was returned
    assertEquals(numResults, results.size());
    // Check that the results are correct and in order
    for (int i = TEST_LIMIT * TEST_PAGE; i < TEST_LIMIT * TEST_PAGE + TEST_LIMIT; i++) {
        assertEquals(result.get(i).getName(), "Name #" + (i + 1));
    }

Now it just so happens that this test is 'correct' in the sense that i will take on the values that I expect it to and ensure that the results are "Name #3" and "Name #4". However it also happens that my queryFunction calculates which results to return in the same way (limit * page + limit kind of thing).

This is concerning because if the test generates the expected answers in the same way that the unit under test does, it won't detect if there's a bug in that approach. However naming the input values with constants makes the tests much more readable than just have magic integers between 1 and 4 plugged in everywhere.

What is the best way to deal with this situation, for both readability and maintainability (e.g. changing values in the future, should you need to)?

Upvotes: 1

Views: 1075

Answers (1)

orlade
orlade

Reputation: 2090

In asking this question I think I've convinced myself that the solution is to define the expected values as constants up front as well, such as:

final int LIMIT = 2, PAGE = 1, MIN_RESULT = 3, MAX_RESULT = 4;

... and then use those values in the assertions. This retains all the readability of named key values, and discourages the temptation to generate the expected outputs. In this case I would still be using a loop to generate each expected name between Name #MIN and Name #MAX, but the bounds themselves would be explicitly static.

Is this as good as it gets, or are there better ways to deal with this repetitiveness?

Upvotes: 1

Related Questions