It is possible to write service tests that verify that a service work even though it has a dependency on an external environment. A database, a JMS server, reading files from file system (or a remote share) are typical examples. We will now describe a concept which makes such a setup manageable.
Abstract description
restoreDefaultState
Our first need is be know what state the system is in when we start a test. Without knowing the state we cannot repeat the test, and we cannot reliably conclude on anything. We can execute queries to detect what state the system is in, but this concept rely on controlling the state. We thus need functionality to restore the default state. I.e., it must be possible to call a function, restoreDefaultState, and be confident that when it finishes we have a known and consistent state every time.
cleanDataAndHistory
Sometimes restoring the default state can be an expensive and time-consuming procedure. It is therefore convenient to have a faster version of the restoreDefaultState function. To make it faster we can skip restoring the datastructures and infrastructure and only delete data and history. Note that application data (f.eks. the version of the database or application) should not be removed.
We suggest the name cleanDataAndHistory for such a function.
When to use
We advocate putting tests into logical groups. It is thus natural to restoreDefaultState before each logical group and to use cleanDataAndHistory between each test within the group.
Dependencies between tests
Be aware that this setup violates the principle of tests being completely self-sufficient. We consider the principle to an anti-pattern, and should be communicated as such.
Another "established" truth we attack is that all dependencies between tests are bad. When writing service tests all tests within a logical group will have the same dependency on the environment. It thus makes sense to test the setup of this environment before running any tests. In the case of a database this "setup test" can be a simple testDatabaseConnection. All tests that require a working database connection should this depend on this test. If testDatabaseConnection fails, all the other tests that depend on it can be skipped and marked with "skipped". This makes it easy to see what caused the build to break and saves execution time.
See TODO testNG reference here.