Friday 1 October 2010

Patterns of Naming Unit Tests

How would you name your test project, test fixtures and test cases?
  • Make sure your naming approach is consistent throughout your project.
  • Make sure names are clear and specific.
  • Each person can invent his/her own pattern of course but these are some common ones:
1) Test Project

Pattern 1
Create a test project per production project and postfix it with "Tests" e.g. "Model.Tests" for the "Model" project. so if you have 10 production projects, create 10 test projects and put then inside a "UnitTests" Visual Studio folder for better grouping.

Example:
  • Project name: Model (as you don't put the name of the Company to the project name)
  • Namespace: Company.Model (namespace would contain the Company name)
  • Assembly name: Company.Model.dll
  • Test project name: Model.Tests
  • Test namespace: Company.Model.Tests
  • Test assembly name: Company.Model.Tests.dll
Pattern 2
Another pattern (or better anti-pattern) is to have one project containing all tests for all projects; I think Pattern 1 is better for simplicity and maintainability so that one would be my preferable choice.

2) Test Fixtures

1 Test fixture per production class.

Pattern 1: "Tests" or "Fixture" Suffix
"Model.Tests.CalculatorTests" or "Model.Tests.CalculatorFixture" for the production class of "Model.Calculator"

Pattern 2: "For." Prefix
"Model.Tests.For.Calculator" for the production class of "Model.Calculator".

The benefit of this naming is that you won't have to repeat the word "Tests" for your fixtures also it would have a nicer readability as you can read it like a sentence "Tests for Calculator" but at the same time, you're adding extra "For." for your classes.

Pattern 1 is often my preferred choice.

3) Test Names

Pattern 1: MethodName_ScenarioOrCondition_ExpectedBehaviour or GivenX_WhenY_ThenZ
  • This pattern has "_" that FXCop doesn't like.
  • It's simple to map which class or method to which test, however, if method names change, you'd want to change your test names as well. Another option is not using the "method name under test" but instead using "behavior under test".
  • This patterns says that, when someone looks at your test name, he should easily find out 1) what is the unit which is being tested? 2) under what condition is it tested? 3) what is the expected behaviour for this condition?
e.g.
public void AnalyzeFile_FileTooShort_ThrowTooShortException()
{
...
}

or

public void GivenAnalyzeFile_WhenFileTooShort_ThenThrowTooShortException()
{
...
}

The second option is easier to read, isn't it?

Pattern 2: WithXShouldY or WhenXExpectY
  • In this pattern, there is no "_" so it makes FXCop happy but of course it reduces readability.
  • The test name has no indication of what method or action therefore, you'd need to put the method name in the test class instead e.g.
Example:

WithEmptyFileNameShouldThrowException or
WhenEmptyFileNameExpectThrowException or
WhenEmptyFileName_ExpectThrowException

ProductionProjectName.Tests
.For.Foobar (test fixture for production feature/component/class/class)
.WhenAnalysing (method, action or behavior)
.WhenEmptyFileNameExpectThrowException (test method name)

Pattern 3: Separate Each Word!
  • This is a very old pattern.
Example:
AnalyzeFile_File_Too_Short_Throw_Too_Short_Exception()

Pattern 4: End method names with "Test"
  • Why would you want to add "Test" to the test name which is attributed with "TestMethod" already?
  • Not my choice.
Example:
AnalyzeFileTest()




No comments: