Guidelines and Best Practices for Unit Tests
This section provides an overview of guidelines and best practices for the unit tests.
Unit tests are those tests that can be executed without running a method server.
While testing the unit test locally on a dev machine, ensure that it runs successfully with the method server stopped.
All unit test names should be ****Test.java.
Write test cases that are independent of each other.
Aim at covering all paths through the unit test.
Use test data that is close to that of production.
Ensure that the unit tests run completely in-memory. For example, do not write unit tests that make HTTP requests, access a database, or read from the file system.
Do not skip the unit tests.
Aim for each unit test method to perform exactly one assertion.
Name unit tests using a convention that includes the method and condition being tested. For example, if the method under test is ‘encode(bytes[])’ and there are test cases testing all possible types of inputs that can be passed (such as, null, empty, too few or too many bytes, etc.) then write individual tests for each of these use cases.
encode_nullBytes
encode_emptyBytes
encode_tooFewBytes
encode_tooManyBytes
encode_rightNumBytes or encode_validBytes
Ensure that the test classes exist in the same Java package as the production class under test.
Ensure that the test code is separated from the production code.
Do not initialize in a unit test class constructor; use an @Before method instead.
Do not use Thread.sleep in unit tests.
Use the most appropriate assertion methods:
Use assertTrue(classUnderTest.methodUnderTest()) rather than assertEquals(true, classUnderTest.methodUnderTest()).
Use assertEquals(expectedReturnValue, classUnderTest.methodUnderTest()) rather than assertTrue(classUnderTest.methodUnderTest().equals(expectedReturnValue)).
Use assertEquals(expectedCollection, classUnderTest.getCollection()) rather than asserting on the collection's size and each of the collection's members.
Put the assertion parameters in a proper order. The parameters to JUnit's assertions are:
a. expected
b. actual
use assertEquals (expected, actual) rather than assertEquals (actual, expected).
Do not write your own catch blocks that exist only to pass a test.
// Don't do this - it's not necessary to write the try/catch!
@Test
public void foo_nine()
{
boolean wasExceptionThrown = false;
try
{
new Foo().foo(9);
}
catch (final IOException e)
{
wasExceptionThrown = true;
}
assertTrue(wasExceptionThrown);
}

// Do this instead
@Test(expected = IOException.class)
public void foo_nine() throws Exception
{
new Foo().foo(9);
}
In test classes, do not declare that methods throw any particular type of exception.
final class Foo
{
int foo(int i) throws IOException;
}
// Don't do this - the throws clause is too specific!
@Test
public void foo_seven() throws IOException
{
assertEquals(3, new Foo().foo(7));
}
Instead, declare that the test method can throw any exception:
// Do this instead
@Test
public void foo_seven() throws Exception
{
assertEquals(3, new Foo().foo(7));
}
Use appropriate annotation while the writing test.
If the method under test calls any other method of another class, then that ‘called’ method could be a candidate for mocking. If, without mocking that ‘called’ method, the test runs successfully without any issue, then mocking may not be needed. Some of the examples where mocking will be needed are when the ‘called’ method needs the method server to perform an operation.
Use mocking of classes carefully. When a class is mocked, the original implementations of existing methods or constructors are temporarily replaced with mock implementations, usually for the duration of a single test.
Was this helpful?