Reputation: 89
I'm writing a test case to test an object behaviour.
When the object is instantiated it must allow the call of a method let say call() only if it has been called within 500 ms, otherwise it must throw an exception.
I designed the Junit test case like this:
@Test(expected = IllegalStateException.class)
public void testCallAfterTimeout() {
MyObject o= new MyObject();
//To ensure the timeout is occurred
Thread.sleep(1000);
o.call();
}
Do you think is a good practice or I should follow another approach?
Many thanks
Upvotes: 8
Views: 14393
Reputation: 20760
There are two problems with using (real) time in test cases:
Thread.sleep()
with in a multithreaded test case this is even more difficult.If you must, your way is acceptable. But there are other options:
Don't use a real clock. Instead use a fake (mocked/stubbed) clock that you can control from your testcase:
@Test(expected = IllegalStateException.class)
public void testCallAfterTimeout() {
MyObject o= new MyObject();
// Example function that you could make
advanceClock(1000, TimeUnit.MILLISECONDS)
o.call();
}
In your object you have to inject a clock. MyObject
could look like this:
class MyObject
{
public MyObject()
{
this(new Clock());
}
// Protected so only the test case can access it
protected MyObject(Clock clock)
{
// Save clock as local variable, store creation time etc.
}
}
In Java 8 a mechanism for this is provided, see for instance LocalDate.now()
. But you can also implement your own quite easily.
Upvotes: 11
Reputation: 8552
Regardless of what is the point of it and that you are asking for trouble ....
What if you decide that timeout needs to occure after 60minutes, will you wait for your test one hour? The timeout should be parameter of your MyObject so you can set it to some small value for testing (or even 0 to force alwyas a timeout when testing).
Secondly, if you want to really have testable time-related functions, the time and timeout should be handled separately from your main logic (MyObject class). You could for example have Timekeeper class with mehtod canCallMethod() which is invoked by your MyObject class (and it is set upon its construction). In that way in your test, you initlize your MyObject class with your own Timekeeper implementation that returns true or false and verify that your MyObject class behaves as expected. MyObject can have default constructor that always uses the 'real' timekeep so external world is not force to deal with Timekeeper internals.
Upvotes: 1