These libraries contain a few classes that I find particularly useful when writing tests:
lastcommons-lang
This library contains a nice system clock abstraction named (unsurprisingly) 'Clock' which was inspired by this StackOverflow answer. A clock instance allows you to get access to various forms of the current time. So far, millis, nanos, java.util.Date, java.util.Calendar, and org.joda.time.DateTime instances are supported. The class does seem too simple to be of any value - after all it just delegates to some standard Java API methods. However, the real power of the abstraction comes when unit testing time dependent code that you may have.In your unit tests you now have the ability to swap out the actual system clock instance with a mock or a stub and take control of the 'current time' - at least as far as the class under test is concerned. This can be very useful as time dependent tests that use the system clock directly can often suffer from the following problems:
Long running tests
You may have some code that should change some state once a minute has elapsed. If using the system clock directly you might call Thread.sleep() to let allow the system clock to advance:
myClass.initialise();
Thread.sleep(TimeUnit.MINUTES.toMillis(1));
myClass.changeState();
assertThat(myClass.getState(), is(/* changed state */));
This will work, but will also result in a test that take no less than one minute to execute. With more tests such delays are compounded and we might end up with a test suite that takes some considerable time to execute. We want tests to be fast so that they are unnoticeable and easy to run. With a mockable clock we could instead write the following and be free from long delays:
when(mockClock.currentTimeMillis()).thenReturn(
0L, TimeUnit.MINUTES.toMillis(1));
myClass.setClock(mockClock);
myClass.initialise();
myClass.changeState();
assertThat(myClass.getState(), is(/* changed state */));
Delays in tests are brittle
You might have another test on a class that should only change state if more than 5 seconds but less than 10 seconds has passed. The problem here is that Thread.sleep() does not guarantee the exact duration of the delay. If your machine is busy the system clock might easily tick by 5 seconds before your thread on which your test is running is rescheduled and your assertion will fail. I have seen this frequently with tests running on continuous-integration machines - tests may run fine for months but if the CI machine is particularly busy, brittle time dependent tests will suddenly start failing. As shown in the previous example - a clock abstraction can removed the need for such delays.
The future
You may wish to test the class for future moments in time and unless you have a time machine - this just isn't practical with the system clock alone. However, you can set a mock or stub clock to whatever time you wish.
lastcommons-test
We really like using JUnit's TemporaryFolder rule for cleanly managing temporary folder and files in our tests. I automatically handles the tear down of the temp fails and removes the need for unsightly path strings in the test code, which in the worst case often end up in a shared constant somewhere. We applied a similar approach to the handling of data files for tests using a DataFolder abstraction. Assuming our standard Maven project layout, implementations allow simple, clean and scoped access to test data. The data folders also allow us to organise test data by test class or even test method without having to worry about the underlying file path. Some examples:Top level data folder
public class MyTest {@Rule
public DataFolder dataFolder = new RootDataFolder();
@Test
public void myTestMethod() throws IOException {
File actualFolder = dataFolder.getFolder();
// Path: ./src/test/data
...
Top level data folder with children
public class MyMp3Test {@Rule
public DataFolder dataFolder
= new RootDataFolder("mp3", "128K", "clean");
@Test
public void myTestMethod() throws IOException {
File actualFolder = dataFolder.getFolder();
// Path: ./src/test/data/mp3/128k/clean
...
Per-class data folder
public class MyTest {@Rule
public DataFolder dataFolder = new ClassDataFolder();
@Test
public void myTestMethod() throws IOException {
File actualFolder = dataFolder.getFolder();
// Path: ./src/test/data/fm/last/project/MyTest
...
Per-method data folder
public class MyTest {@Rule
public DataFolder dataFolder = new MethodDataFolder();
@Test
public void myTestMethod() throws IOException {
File actualFolder = dataFolder.getFolder();
// Path: ./src/test/data/fm/last/project/MyTest/myTestMethod