Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

In researching unit testing best practices to help put together guidelines for my organization, I've run into the question of whether it is better or useful to separate test fixtures (test classes) or to keep all tests for a single class in one file.

Fwiw, I am referring to "unit tests" in the pure sense that they are white-box tests targeting a single class, one assertion per test, all dependencies mocked, etc.

An example scenario is a class (call it Document) that has two methods: CheckIn and CheckOut. Each method implements various rules, etc. that control their behavior. Following the one-assertion-per-test rule, I will have multiple tests for each method. I can either place all of the tests in a single DocumentTests class with names like CheckInShouldThrowExceptionWhenUserIsUnauthorized and CheckOutShouldThrowExceptionWhenUserIsUnauthorized.

Or, I could have two separate test classes: CheckInShould and CheckOutShould. In this case, my test names would be shortened but they'd be organized so all tests for a specific behavior (method) are together.

I'm sure there are pro's and con's to either approach and am wondering if anyone has gone the route with multiple files and, if so, why? Or, if you've opted for the single file approach, why do you feel it is better?

share|improve this question
    
Your test method names are too long. Simplify them, even if it means a test method would contain multiple assertions. –  Bernard Dec 13 '11 at 15:00
8  
@Bernard: it is considered bad practice to have multiple assertions per method, long test method names are however NOT considered bad practice. We usually document what the method is testing in the name itself. E.g. constructor_nullSomeList(), setUserName_UserNameIsNotValid() etc... –  c_maker Dec 13 '11 at 15:14
2  
@Bernard: i use long test names (and only there!) too. I love them, cause it is so clear what was not working (if your names are good choices ;)). –  Sebastian Bauer Feb 3 '12 at 5:26

6 Answers 6

Can't really see any compelling reason why you would split a test for a single class into multiple test-classes. Since the driving idea should be to maintain cohesion on a class-level, you should strive for it on a test-level as well. Just some random reasons:

  1. No need to duplicate (and maintain multiple versions of) set-up code
  2. Easier to run all tests for a class from an IDE if they are group in one test-class
  3. Easier troubleshooting with one-to-one mapping between test-classes and classes.
share|improve this answer
    
Good points. If the class under test is an awful kludge, I would not rule out several test classes, where some of them contain helper logic. I just do not like very rigid rules. Other than that, great points. –  Job Dec 13 '11 at 15:10
1  
I'd eliminate duplicate setup code by having a common base class for the test fixtures working against a single class. Not sure I agree with the other two points at all. –  SonOfPirate Dec 13 '11 at 15:29

If you are compelled to split unit tests for a class across multiple files, that may be an indication that the class itself is poorly designed. I can't think of any scenario where it would be more beneficial to split up the unit tests for a class that reasonably adheres to the Single Responsibility Principle and other programming best practices.

Furthermore, having longer method names in unit tests is acceptable, but if it bothers you, you can always rethink your unit test naming convention to shorten the names.

share|improve this answer
    
Alas, in the real world not all classes adhere to SRP et al... and this becomes an issue when you are unit testing legacy code. –  Péter Török Dec 13 '11 at 15:12
2  
Not sure how SRP relates here. I have multiple methods in my class and I need to write unit tests for all of the different requirements that drive their behavior. Is it better to have one test class with 50 test methods or 5 test classes with 10 tests each that relate to a specific method in the class under test? –  SonOfPirate Dec 13 '11 at 15:30
2  
@SonOfPirate: If you need so many tests, that might mean your methods are doing too much. So SRP is very much relevant here. If you apply SRP to classes as well as methods, you will have lots of small classes and methods that are easy to test and you will not need so many test methods. (But I agree with Péter Török that when you test legacy code, good practices are out the door and you just have to do the best you can with what you are given...) –  c_maker Dec 13 '11 at 15:47
    
Best example I can give is the CheckIn method where we have business rules that determine who is allowed to perform the action (authorization), if the object is in the proper state to be checked in such as if it is checked-out and if changes have been made. We will have unit tests that verify the authorization rules are being enforced as well as tests to verify that the method behaves correctly if CheckIn is called when the object is not checked-out, not changed, etc. That is why we end up with many tests. Are you suggesting this is wrong? –  SonOfPirate Dec 13 '11 at 16:12
    
I don't think there are hard-and-fast, right-or-wrong answers on this subject. If what you're doing is working for you, that's great. This is just my perspective on a general guideline. –  FishBasketGordo Dec 13 '11 at 16:30

It's rare, but sometimes it makes sense to have multiple test cases for a given class. Typically I would do this when different setups are required, and shared across a subset of the tests.

share|improve this answer
2  
Good example why that approach was presented to me in the first place. For instance, when I want to test the CheckIn method, I always want the object under test to be setup one way but when I test the CheckOut method, I require a different setup. Good point. –  SonOfPirate Dec 13 '11 at 15:32

One of my arguments against separating the tests into multiple classes is that it becomes harder for other developers on the team (especially those who aren't as test savvy) to locate the existing tests (Gee I wonder if there is already a test for this method? I wonder where it would be?) and also where to put new tests (I'm going to write a test for this method in this class, but not quite sure if I should put them in a new file, or an existing one?)

In the case where different tests require drastically different setups, I have seen some practitioners of TDD put the "fixture" or the "setup" in different classes/files, but not the tests themselves.

share|improve this answer

In general I would recommend thinking about tests as testing a behaviour of the class rather than a method. I.e. some of your tests may need to call both methods on the class in order to test some expected behaviour.

Usually I start out with one unit test class per production class, but may eventually split that unit test class into several test classes based on the behaviour they tests. In other words I would recommend against splitting the test class into CheckInShould and CheckOutShould, but rather splitting by behaviour of the unit under test.

share|improve this answer
up vote 1 down vote accepted

I wish I could remember/find the link where the technique I've chosen to adopt was first demonstrated. Essentially I create a single, abstract class for each class under test that contains nested test fixtures (classes) for each member being tested. This provides the separation originally desired but keeps all of the tests in the same file for each location. In addition, this generates a class name that allows easy grouping and sorting in the test runner.

Here is an example how this approach is applied to my original scenario:

public abstract class DocumentTests : TestBase
{
    [TestClass()]
    public sealed class CheckInShould : DocumentTests
    {
        [TestMethod()]
        public void ThrowExceptionWhenUserIsNotAuthorized()
        {
        }
    }

    [TestClass()]
    public sealed class CheckOutShould : DocumentTests
    {
        [TestMethod()]
        public void ThrowExceptionWhenUserIsNotAuthorized()
        {
        }
    }
}

This results in the following tests appearing in the test list:

DocumentTests+CheckInShould.ThrowExceptionWhenUserIsNotAuthorized
DocumentTests+CheckOutShould.ThrowExceptionWhenUserIsNotAuthorized

As more tests are added, they are easily grouped and sorted by class name which also keeps all tests for the class under test listed together.

Another advantage of this approach that I've learned to leverage is the object-oriented nature of this structure means I can define code inside the startup and cleanup methods of the DocumentTests base class that will be shared by all nested classes as well as inside each nested class for the tests it contains.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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