-
Notifications
You must be signed in to change notification settings - Fork 14
Test practices
-
Keep tests small and fast
-
Try to Write one test-condition per test method
-
Use the strongest assertions possible
In order of decreasing strength, assertions fall into the falling categories:
- strongest assertions - asserting on the return value of a method;
- strong assertions - verifying that vital dependent mock objects were interacted with correctly;
- weak assertions - verifying that non-vital dependent mock objects (such as a logger) were interacted with correctly;
- non-existent assertions.
-
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 assertion parameters in the proper order
For example, use assertEquals(expected, actual) rather than assertEquals(actual, expected).
Remember that assertThat(actual, expected).
-
Use assertions with message in case of multiple assertions in one method
For example, use assertEquals(message, expected, actual) in integration tests.
-
Use exact matching when using a mocking framework
For example, avoid using Mockito's methods that start with any; prefer configuring and verifying exact parameter values.
-
Name unit tests using a convention that includes the method and condition being tested
Test methods' names within the test case should describe what they test:
- testLoggingEmptyMessage()
- testLoggingNullMessage()
- testLoggingWarningMessage()
- testLoggingErrorMessage()
- createEmployee_NullId_ShouldThrowException
- createEmployee_NegativeId_ShouldThrowException
- testCreateEmployee_DuplicateId_ShouldThrowException
Proper naming helps code readers understand each test's purpose.
-
Ensure that test classes exist in the same Java package as the production class under test
When in the same package as the production class being tested, test classes can use package-private classes and invoke package-private methods.
-
Ensure that test code is separated from production code
The default folder structure in a Maven project does this - production code exists in the src/main/java folder and test code exists in the src/test/java folder. Even if you don't use Maven, put test code and production code in different folders.
-
Do not initialize in a unit test class constructor; use an @Before method instead
If a failure occurs during a test class constructor, an AssertionFailedError occurs and the stack trace is not very informative; in particular, the stack trace does not include the original error's location. On the other hand, if a failure occurs during an @Before method, all details about the failure's location are available.
JUnits lifecycle:
- Create a different testclass instance for each test method
- Repeat for each testclass instance: call setup + call the testmethod
-
Do not use static not final members in a test class
Static members make unit test methods dependent. Don't use them! Instead, strive to write test methods that are completely independent.
-
In test classes, do not declare that methods throw any particular type of exception
Test methods that declare that they throw one particular type of exception are brittle because they must be changed whenever the method under test changes.
-
Do not use Thread.sleep in unit tests
When a unit test uses Thread.sleep it does not reliably indicate a problem in the production code. For example, such a test can fail because it is run on a machine that is slower than usual. Aim for unit tests that fail if and only if the production code is broken.
Rather than using Thread.sleep in a unit test, refactor the production code to allow the injection of a mock object that can simulate the success or failure of the potentially long-running operation that must normally be waited for.
-
Don't assume the order in which tests within a test case run
Running the tests on different platforms and Java VMs may therefore yield different results, unless your tests are designed to run in any order.
-
Call a superclass's setUp() and tearDown() methods when subclassing
setUp() should call super.setUp() to ensure that all environment of super class are running.
-
Do not load data from hard-coded locations on a filesystem
-
Document tests in javadoc
-
Avoid visual inspection
Testing servlets, user interfaces, and other systems that produce complex output is often left to visual inspection. Visual inspection -- a human inspecting output data for errors -- requires patience, the ability to process large quantities of information, and great attention to detail: attributes not often found in the average human being. Below are some basic techniques that will help reduce the visual inspection component of your test cycle.
From