The key to reduce this time is writing maintainable unit tests - and the following rules should help here:
(Note that this is work in progress – I will edit rules and add new ones any time)
Unit Test Design Rules
Every test method should have exactly one goal
- Before writing a test, think about what exactly you want to test
- Don't handle different test cases with a single test method - use multiple methods instead
- Every test must have at least one assertion
The name of the test method should reflect its purpose
- The method name should be a summary of the test case
- With TestNG, you may use @Test(description) instead
- And, please: don't prefix methods with "test"…
A test should be easy to read
- A test that reads like a specification or DSL is easy to understand and therefore easy to maintain
- Use the GIVEN-WHEN-THEN template
- Encapsulate complex GIVEN and WHEN clauses in private methods
A test should be independent, thread-safe, and free of side effects
- Tests with dependencies or side effects lead to hard-to-find errors
- Tests that require a database must not be data dependent (no assumptions about existing data) and must not leave traces in the database
- Don't ever use TestNG's @Test(dependsOnMethods) attribute
- Some frameworks support parallel test execution – better be prepared!
Don't use inheritance
- Test classes should be final, so that tests cannot be overwritten or reused by subclasses
- You may use abstract superclasses for easier code reuse, but these classes must not contaqin any tests
Use mocking - but use it with care
- Mocking remote interfaces and external resources will improve test performance and stability
- But mocking adds complexity to your test!
- Mock only things that really need to be mocked (don't use all features of your mocking framework just because you can)
Avoid using in-memory-databases for tests
- If your test is dependent of a database (it really is?) then you should use the real target platform - otherwise the test won't have much value
- If your test is database-independent, then you should try to mock all database accesses and run without any database
Tools for Unit Testing
|JUnit||Still my favorite unit testing framework - small, simple, stable|
|TestNG||Has a lot more features than JUnit (for me, the most important are data providers and parallel test execution), but that comes with great complexity (what looks like a bug in your code or test may turn out to be a bug in the testing framework).|
I try to stick to JUnit and use TestNG only for complex requirements.
|Hamcrest||This is a great extension of JUnit and TestNG, since the assert statements of these frameworks are very poor (JUnit even uses the "wrong" order of arguments).|
It greatly increases the readability of assertions (DSL-like).
|FEST||Provides fluent assertions, which are even nicer than Hamcrest (and don’t have those issues with generics)|
|Easymock||I use only very basic mocking features, so possibly any mocking framework would suffice.|
Easymock was the first one I looked at, it has a nice and intuitive API - so I took it without evaluating any other.