12

I am writing JUnit unit tests for my classes.

Is it better to have a separate class for each method, or have just one test class for every actual class?

15

How your tests are organized is rather unimportant compared to the importance of having them at all.

The most important thing for a good test suite is that it covers all of the functionality; that ensures that whenever a regression defect is introduced, you'll notice right away. Whether to write one test for each method, one test for each input value combination of a method, or even one test for each possible code path within that method is less important. Whether to organize these tests into few or many test classes is even less important: a test suite should always succeed in full, so it doesn't matter whether it fails one of three or two out of seventeen tests - both are wrong and must be fixed.

Of course, test code is also code, so it should follow the normal best practices for being maintainable, modular, etc. But that must be decided by how well-maintainable the test suite itself is, not by how the test classes relate to the classes they test. Both of the policies you mention can help you remember where to find things if you follow them consistently, but for that the consistency is more important than the choice of policy.

5

To your specific question, the junit convention is to have a 1-1 correspondence between your application classes (Foo1.java, Foo2.java) and junit test classes (Foo1Test.java, Foo2Test.java) -- http://junit.sourceforge.net/doc/faq/faq.htm#tests_13

That said, I agree wholeheartedly with Kilian's highlighting of the importance of the spirit/goals of unit testing over any organizational schemes that might be used. Pick some conventions and stick with them most of the time, while guardedly allowing exceptions to your conventions when they're warranted.

3

Is it better to have a separate class for each method, or have just one test class for every actual class?

If you have the need to write separate test classes for methods of one class, then you have the wrong design. Methods should be small, easy to read, easy to test and easy to change. The tests could be a bit longer, than the original code due to making up testdata, mocking etc. but should not be significantly longer. If they are, your class under test is too complex and does for sure more than one thing (single responsibility principle). Work on your design.

1

I think it's right that each class has its test class. The idea is to centralize all unit tests related to the target class in a single test class. Then, for example, MyClass.java will have its test class, MyClassTest.java.

1

I think both "one testclass per method" and "one testclass per class" are usually too extreme.

In general you want to have one check per testmethod/unittest, this could be multiple assertions to for example check that a list.isEmpty=true and list.Length=0, so one testmethod/unittest per behavior.
This makes it easy to come up with a testmethod name that describes the behavior. You want to group testmethods in a testclass so when you read the testclassname.testmethod it makes sense. Usually those have some shared setupcode which is then easy to put in the test setup/fixture. Depending on the class under test, this can be one testclass for the whole class, and it can also be one testclass for one method. But usually it will be somewhere in between.

As with normal code, you want to have the tests as readable as possible. What helps for me is following the BDD given-when-then or arrange-act-assert style of organizing the testcode. A testclass could have that given, its setup. Then every testmethod in that class uses that given (or part of it) and has one when and one then.
Think also of the unittests as documentation on how to use functionality of the class under test. With good unittests, you can read the tests to find out how to use the functionality of the class you want to use, and what the effects will be exactly.
When something breaks and a unittest fails, you want it to be as easy as possible to understand what broke, one assertion per test helps a lot here. When there are multiple assertions in one test, only the first one fails and then the method exits, so you don't know if the other behavior tested in the following tests is also broken until you fix the thing that made the first assertion fail. With one assertion, all your other testmethods still get executed and its much faster to understand the depth of the fail.

Of course I agree with Kilian Foth, in practice you can be lucky to have a few unittests for code you are working on. And any small localized test is better than no test at all, or only big integration tests that run on the buildserver, take a lot of time and usually arent very localized (they don't tell you fast where the error is, you'll have to work on it a little).

  • Good point: "You want to group testmethods in a testclass so when you read the testclassname.testmethod it makes sense". – MAChitgarha Jan 11 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.