2

I have a method that I need to test that has multiple cases that need to be tested, and each case requires a few lines of code to test. Before long the test function is 50 lines long and it is a bit difficult to find the failures. (No, this function is not able to be reasonably split into reasonably small and easily testable methods.)

Are test methods intended to be specifically for one method, and no other test cover that method, or is it ok to have multiple test methods cover differnt aspects of a function? Example:

@Test
public void testSomeComplexMethod() {
    // lots of code
}

// or

@Test
public void testSomeComplexMethodAspect1() {
    // a little code that just tests aspect 1
}

@Test
public void testSomeComplexMethodAspect2() {
    // a little code that just tests aspect 2
}
J Atkin
  • 163
  • 7
  • It is recommended to have multiple tests for each method, and each of them should only test "one thing". The reason being that otherwise you loose all possibly usefull information about test cases further down your test method if one of them fails. – Hulk Feb 10 '17 at 08:44

3 Answers3

5

It is totally ok to have several test methods for testing the behaviors of a single method in the SUT. In fact, I strongly encourage you to do so unless the functionality can be tested using some kind of data-driven test (see e.g. NUnit's TestCase attribute).

Example similar to yours, just using a different naming convention:

@Test
public void someComplexMethod_BehavesLikeThis_WhenTheseConditionsApply() {
    // a little code that just tests behavior 'like this' given 'these conditions'
}

Going off on a tangent:

(No, this function is not able to be reasonably split into reasonably small and easily testable methods.)

I have a hard time believing this is actually true. The function itself might be hard to split, but the underlying code can almost always be extracted into separate entities that can be more easily tested in isolation - changing the original function to more of an 'orchestrator' that uses the new parts.

rjnilsson
  • 399
  • 2
  • 4
3

The great thing about unit testing is that you will know exactly what is wrong if a given test failed.

You do not have this feature in higher-levels of testing - they have other purposes.

Each unit test should have one and only one reason to failed (in same cases, you could need more than one assert to check this reason). If you can modify the target function at more than one point and make the same test failed, you should try to split the test. That's the purpose of mutation testing.

OBS:

If your unit testing framework has features like PHPUnit's @covers annotation, you should use it to ensure you are covering exactly the case you expect with a test.

João Farias
  • 139
  • 3
0

Another benefit of having multiple tests is that you can factor out the common functionality into what are called utility functions.

Usually you'll find after a few tests that they are all doing the same kind of setup, and setting the same properties for the conditions. But the values for the conditions are going to vary.

The result is that when you factor out the commonalities, you end up just passing in the different conditions to your utility functions to handle the setup.

This has two effects.

One, it answers the old question about how you test your test code. Utility functions are reused, so automatically tested. If all the tests fail, the problem is probably in the function or the setup of the SUT. If only one fails, it is in the test itself or the behavior you are trying to test.

Two, with less noise your code is cleaner, the intent is more evident, tests are easier to read and maintain.

Any setup you want to do that does not vary test to test, and so doesn't need any parameters, goes into the [Setup] routine.

Lastly, I break groups of tests into separate classes when they need a separate [Setup] on the theory that you are testing something separate.

BWhite
  • 101