Unit testing time-based logic in Java - java

I have a method which implements different logic on data fetched from a DB depending on what the current date is.
I want to test it by having the unit test create objects, save them in the DB and invoke the tested method. However, in order to have predictable results I need to change the system date each time and I don't know how to do that in Java.
Suggestions?

You can generate your expected results using the current date.
Or you write your system to use a date/time you give it when being tested (rather than the clock) That way the time is always what the test expects.
I use something like
interface TimeSource {
long currentTimeMS(); // actually I have currentTimeNS
void currentTimeMS(long currentTimeMS);
}
enum VanillaTimeSource implements TimeSource {
INSTANCE;
#Override
public long currentTimeMS() {
return System.currentTimeMillis();
}
#Override
public void currentTimeMS(long currentTimeMS) {
// ignored
}
}
class FixedTimeSource implements TimeSource {
private long currentTimeMS;
#Override
public long currentTimeMS() {
return currentTimeMS;
}
#Override
public void currentTimeMS(long currentTimeMS) {
this.currentTimeMS = currentTimeMS;
}
}
In tests I use a FixedTimeSource which can be data driven e.g. set by inputs/events. In production I use a VanillaTimeSource.INSTANCE which ignores times in inputs/events and uses the current time.

You need to look at injecting something into your class that allows you to customize the way Time is presented.
For example
public interface TimeProvider {
DateTime getCurrentTime();
}
public class UnderTest {
// Inject this in some way (e.g. provide it in the constructor)
private TimeProvider timeProvider;
public void MyMethod() {
if (timeProvider.getCurrentTime() == "1234") {
// Do something
}
}
}
Now in your unit tests you can provide a fake implementation of time provider. In the real production code you can just return the current date time.

I had a similar problem recently with code I couldn't refactor too much (time constraints, didn't want to inadvertently break anything). It had a method I wanted to test which called System.currentTimeMillis() and the case I wanted to test would depend on what that value returned. Something like:
public class ClassINeedToTest {
public boolean doStuff() {
long l = System.currentTimeMillis();
// do some calculation based on l
// and return the calculation
}
}
To allow unit-testing, I refactored the class so it had a helper method which was protected
protected long getCurrentTimeMillis() {
// only for unit-testing purposes
return System.currentTimeMillis();
}
and this method was called by doStuff(). This didn't change the functionality but now meant that when I call it in the unit-test, I could then override this to return a specific value, like
ClassINeedToTest testClass = new ClassINeedToTest() {
protected long getCurrentTimeMillis() {
// return specific date for my test
return 12456778L;
}
};
boolean result = testClass.doStuff();
// test result with an assert here
This does however mean that I've polluted the interface of my class, so you may decide the cost is too high. There are probably better ways if you can refactor the code more.

Related

How can I test an Aggregate that relies on time?

I am trying to model a time keeping application.
Ordinarily when I have a class that depends on time, I can provide an overloaded constructor or method to be able to inject a Clock into that method or class and be able to test its behavior.
If I have a command that needs to be able to pass the current time into an event, how can this work in the aggregate of an axon based application?
#Aggregate
#Slf4j
public class TimeCard {
#AggregateIdentifier
private String employeeName;
private Instant clockInTime;
public TimeCard() {
//Axon requires empty constructor on aggregate
}
#CommandHandler
public TimeCard(ClockInCommand cmd) {
AggregateLifecycle.apply(new ClockInEvent(cmd.getEmployeeName(), Instant.now()));
}
#EventSourcingHandler
public void on(ClockInEvent event) {
this.employeeName = event.getEmployeeName();
this.clockInTime = event.getClockInTime();
}
}
It seemed that the test fixture handled that cleanly for me by providing methods to provide the time. Here is my test method:
#Test
void testClockInCommand() {
testFixture.givenNoPriorActivity()
.andGivenCurrentTime(clock.instant())
.when(new ClockInCommand("GoldFlsh"))
.expectEvents(new ClockInEvent("GoldFlsh", testFixture.currentTime()));
}
But my event did end up being different by a fraction of a second.
Expected <2020-02-02T13:47:20.684344700Z> but got <2020-02-02T13:47:20.954347700Z>
What's the best way to handle this? Should commands only take in time from upstream? Or can I inject a clock somehow for testing.
When relying on time in Aggregates (and other axon types) you can use the GenericEventMessage.clock which defaults to System.UTC in most runtime configurations.
The Testfixture will override this to be a fixed time during tests. Update the use of Instant.now() to use this clock.
#CommandHandler
public TimeCard(ClockInCommand cmd) {
AggregateLifecycle.apply(new ClockInEvent(cmd.getEmployeeName(), GenericEventMessage.clock.instant()));
}

Mockito, verify that line not executed for some condition inside one test method

Im writing unit test using testng and mockito.
Im normally practice to call one method few times inside same test method by using different values / condition to check all scenarios.
Please dont think about the logic, and design i have provided. this is just sample for clear what actually i want to make.
Review code below.
public class Human {
private String name;
private boolean parent;
private List<Human> childs = new ArrayList<>();
public String getName() {
return name;
}
public boolean isParent() {
return parent;
}
public void setParent(boolean parent) {
this.parent = parent;
}
public void addChild(List<Human> childs) {
this.childs = childs;
}
public List<Human> getChilds() {
return childs;
}
}
public class Validator {
public boolean isParent(Human human) {
if (null == human) {
return false;
}
if (human.isParent()) {
return true;
}
if (human.getChilds().size() > 0) {
return true;
}
return false;
}
}
Im writing test case for Validator isParent method by using mockito.
public class ValidatorTest {
public void testIsParent() throws Exception {
Validator validator = Mockito.spy(new Validator());
Human human = Mockito.mock(Human.class);
Mockito.when(human.isParent()).thenReturn(false);
boolean isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
Mockito.when(human.isParent()).thenReturn(true);
isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
}
In here i want to verify that getChilds() never call for second method call to validator.isParent(human) because mocked human set to return true when call human.isParent();
I used Mockito.verifyZeroInteractions() but it says fail
As i understand Mockito.verifyZeroInteractions() check through all test. not only for particular method call.
I want to know is there some way to verify that method is not call for some cases and method call for same cases within same test method.
Or should i should practice test one scenario in one test method.
It's a good practice to have "one scenario per one one test method" (see How many unit tests should I write per function/method? )
Technically it's still possible to reset mocks with Mockito.reset(...), but this what official documentation says about it:
Smart Mockito users hardly use this feature because they know it could be a sign of poor tests.
Normally, you don't need to reset your mocks, just create new mocks for each test method.
Instead of reset() please consider writing simple, small and focused test methods over lengthy, over-specified tests. First potential code smell is reset() in the middle of the test method. This probably means you're testing too much. Follow the whisper of your test methods: "Please keep us small & focused on single behavior".
See https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html#17
The verify method can accept a second argument where you can specify how many times the method has been called. You can use this to say the method was never called, called once, twice etc.
For example:
import static org.mockito.Mockito.never;
...
public void testIsParent() throws Exception {
Validator validator = Mockito.spy(new Validator());
Human human = Mockito.mock(Human.class);
Mockito.when(human.isParent()).thenReturn(false);
boolean isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
Mockito.when(human.isParent()).thenReturn(true);
isParent = validator.isParent(human);
Mockito.verify(human, never()).getChilds();
}
The documentation for this is here: http://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html#4
I want to point out that this question seriously abuses mocking, for testing something that can easily and cleanly be tested without any mocks.
This is what the tests should look like:
public class ValidatorTest {
final Validator sut = new Validator();
#Test
public void checkThatNoHumanIsNotAParent() {
boolean isParent = sut.isParent(null);
assertFalse(isParent);
}
#Test
public void checkHumanThatIsNotAParent() {
Human notAParent = new Human();
boolean isParent = sut.isParent(notAParent);
assertFalse(isParent);
}
#Test
public void checkParentHumanWithNoChildIsAParent() {
Human parentWithNoChildren = new Human();
parentWithNoChildren.setParent(true);
boolean isParent = sut.isParent(parentWithNoChildren);
assertTrue(isParent);
}
#Test
public void checkHumanNotMarkedAsParentButWithChildIsAParent() {
Human humanWithChildren = new Human();
Human child = new Human();
humanWithChildren.addChild(child);
boolean isParent = sut.isParent(humanWithChildren);
assertTrue(isParent);
}
}
These tests completelly exercise all four scenarios. They are clearly much better than a version that uses mocking. Finally, note that Mockito's documentation (in the page on how to write good tests) also says that value objects (such as Human) should not be mocked.

what's a good pattern for registering a Class to execute a specific task later on?

I'm writing a test suite, and I'm thinking about how to mock certain request/response flows. For example, I want to test a method that makes multiple RESTful calls:
getCounts() {
...
Promise<Integer> count1 = getCount1();
Promise<Integer> count2 = getCount2();
// returns a DataModel containing all counts when the Promises redeem
}
getCount1() {
...
Request<Foo> request = new Request<Foo>();
sendRequest(request);
...
}
getCount2() {
...
Request<Bar> request = new Request<Bar>();
sendRequest(request);
...
}
sendRequest(Request<T> request) {...}
However, each getCount() method creates a different Request<T> object, where <T> describes the type of request being made in regards to the count being retrieved. This means I can't simply "mock" the sendRequest() method since it is being called with a different type each time.
I was thinking about an approach where I register a "handler"... when sendRequest() is called, it determines which handler to call, and the handler would know the appropriate type of mock data to return. The registration would be something like storing the handler class type or an instance of the handler class along with the mock data it needs, and when sendRequest() is called, it would look for and invoke the correct handler.
However, I'm not sure if this a good pattern, and I'm wondering if there is a better way of approaching this problem. What is a good pattern for registering a Class or a particular method to execute a specific task later on?
Hard to answer without more context, but the general approach is to use Inversion Of Control (IOC). For example, put the getCountXXX methods into a class of their own, which may be a good idea for better reuse, readability, encapsulation, testability, etc:
public class CountFetcher {
getCount1() { ... }
getCount2() { ... }
}
The original code now gets an instance of CountFetcher using whatever "injection" mechanism is available to you. Simplest is just a constructor:
public class Counter {
private final CountFetcher fetcher;
public Counter(CountFetcher fetcher) {
this.fetcher = fetcher;
}
public getCounts() {
Promise<Integer> count1 = fetcher.getCount1();
Promise<Integer> count2 = fetcher.getCount2();
...
}
}
In your production code, you instantiate Counter with a real CountFetcher. In test code, you inject a mock version of CountFetcher which can have each individual getCountXXX method return whatever you want:
public class MockCountFetcher extends CountFetcher {
#Override
getCount1() { return mockCount1; }
}
public class TestCounter {
#Test
public void smokeTest() {
CountFetcher mockFetcher = new MockCountFetcher();
Counter counter = new Counter(mockFetcher);
assertEquals(someExpectedValue, counter.getCounts());
}
}

How to test passing of time in jUnit test without accessing private variables?

I'm unit testing a class where I need a certain amount of time to pass before I can check results. Specifically I need x minutes to pass before I can tell whether the test worked or not. I have read that in unit testing we should be testing the interface and not the implementation, so we should not be accessing private variables, but other than putting a sleep in my unit test I don't know how to test without modifying private variables.
My test is set up like this:
#Test
public void testClearSession() {
final int timeout = 1;
final String sessionId = "test";
sessionMgr.setTimeout(timeout);
try {
sessionMgr.createSession(sessionId);
} catch (Exception e) {
e.printStackTrace();
}
DBSession session = sessionMgr.getSession(sessionId);
sessionMgr.clearSessions();
assertNotNull(sessionMgr.getSession(sessionId));
Calendar accessTime = Calendar.getInstance();
accessTime.add(Calendar.MINUTE, - timeout - 1);
session.setAccessTime(accessTime.getTime()); // MODIFY PRIVATE VARIABLE VIA PROTECTED SETTER
sessionMgr.clearSessions();
assertNull(sessionMgr.getSession(sessionId));
}
Is it possible to test this other than modifying the accessTime private variable (via creating the setAccessTime setter or reflection), or inserting a sleep in the unit test?
EDIT 11-April-2012
I am specifically trying to test that my SessionManager object clears sessions after a specific period of time has passed. The database I am connecting to will drop connections after a fixed period of time. When I get close to that timeout, the SessionManager object will clear the sessions by calling a "finalise session" procedure on the database, and removing the sessions from it's internal list.
The SessionManager object is designed to be run in a separate thread. The code I am testing looks like this:
public synchronized void clearSessions() {
log.debug("clearSessions()");
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, - timeout);
Iterator<Entry<String, DBSession>> entries = sessionList.entrySet().iterator();
while (entries.hasNext()) {
Entry<String, DBSession> entry = entries.next();
DBSession session = entry.getValue();
if (session.getAccessTime().before(cal.getTime())) {
// close connection
try {
connMgr.closeconn(session.getConnection(), entry.getKey());
} catch (Exception e) {
e.printStackTrace();
}
entries.remove();
}
}
}
The call to connMgr (ConnectionManager object) is a bit convoluted, but I am in the process of refactoring legacy code and it is what it is at the moment. The Session object stores a connection to the database as well as some associated data.
The test could do with some refactoring to make the intent clearer. If what I comprehend is correct...
.
public void TestClearSessionsMaintainsSessionsUnlessLastAccessTimeIsOverThreshold() {
final int timeout = 1;
final String sessionId = "test";
sessionMgr = GetSessionManagerWithTimeout(timeout);
DBSession session = CreateSession(sessionMgr, sessionId);
sessionMgr.clearSessions();
assertNotNull(sessionMgr.getSession(sessionId));
session.setAccessTime(PastInstantThatIsOverThreshold()); // MODIFY PRIVATE VARIABLE VIA PROTECTED SETTER
sessionMgr.clearSessions();
assertNull(sessionMgr.getSession(sessionId));
}
Now to the matter of testing without having to expose private state
How is the private variable modified in real life ? Is there some other public method you could call which updates the access time?
Since the clock/time is an important concept, why not make that explicit as a role. So you could pass a Clock object to the Session, which it uses to update its internal access time. In your tests, you could pass in a MockClock, whose getCurrentTime() method would return whatever value you wish. I'm making up the mocking syntax.. so update with whatever you are using.
.
public void TestClearSessionsMaintainsSessionsUnlessLastAccessTimeIsOverThreshold() {
final int timeout = 1;
final String sessionId = "test";
expect(mockClock).GetCurrentTime(); willReturn(CurrentTime());
sessionMgr = GetSessionManagerWithTimeout(timeout, mockClock);
DBSession session = CreateSession(sessionMgr, sessionId);
sessionMgr.clearSessions();
assertNotNull(sessionMgr.getSession(sessionId));
expect(mockClock).GetCurrentTime(); willReturn(PastInstantThatIsOverThreshold());
session.DoSomethingThatUpdatesAccessTime();
sessionMgr.clearSessions();
assertNull(sessionMgr.getSession(sessionId));
}
It looks like functionality being tested is SessionManager evitcs all expired sessions.
I would consider creating test class extending DBSession.
AlwaysExpiredDBSession extends DBSession {
....
// access time to be somewhere older 'NOW'
}
EDIT: I like Gishu's answer better. He also encourages you to mock the time, but he treats it as a first class object.
What exactly is the rule you're trying to test? If I'm reading your code right, it looks like your desire is to verify that the session associated with the ID "test" expires after a given timeout, correct?
Time is a tricky thing in unit tests because it's essentially global state, so this is a better candidate for an acceptance test (like zerkms suggested).
If you still want to have a unit test for it, generally I try to abstract and/or isolate references to time, so I can mock them in my tests. One way to do this is by subclassing the class under test. This is a slight break in encapsulation, but it works cleaner than providing a protected setter method, and far better than reflection.
An example:
class MyClass {
public void doSomethingThatNeedsTime(int timeout) {
Date now = getNow();
if (new Date().getTime() > now.getTime() + timeout) {
// timed out!
}
}
Date getNow() {
return new Date();
}
}
class TestMyClass {
#Test
public void testDoSomethingThatNeedsTime() {
MyClass mc = new MyClass() {
Date getNow() {
// return a time appropriate for my test
}
};
mc.doSomethingThatNeedsTime(1);
// assert
}
}
This is a bit of a contrived example, but hopefully you get the point. By subclassing the getNow() method, my test is no longer subject to the global time. I can substitute whatever time I want.
Like I said, this breaks encapsulation a little, because the REAL getNow() method never gets tested, and it requires the test to know something about the implementation. That's why it's good to keep such a method small and focused, with no side effects. This example also assumes the class under test is not final.
Despite the drawbacks, it's cleaner (in my opinion) than providing a scoped setter for a private variable, which can actually allow a programmer to do harm. In my example, if some rogue process invokes the getNow() method, there's no real harm done.
I basically followed Gishu's suggestion https://stackoverflow.com/a/10023832/1258214, but I thought I would document the changes just for the benefit of anyone else reading this (and so anyone can comment on issues with the implementation). Thank you to the comment's pointing me to JodaTime and Mockito.
The relevant idea was to recognise the dependency of the code on time and to extract that out (see: https://stackoverflow.com/a/5622222/1258214). This was done by creating an interface:
import org.joda.time.DateTime;
public interface Clock {
public DateTime getCurrentDateTime() ;
}
Then creating an implementation:
import org.joda.time.DateTime;
public class JodaClock implements Clock {
#Override
public DateTime getCurrentDateTime() {
return new DateTime();
}
}
This was then passed into SessionManager's constructor:
SessionManager(ConnectionManager connMgr, SessionGenerator sessionGen,
ObjectFactory factory, Clock clock) {
I was then able to use code similar to what Gishu suggested (note the lower case 't' at the beginning of testClear... my unit tests were very successful with the upper case 'T' until I realised that the test wasn't running...):
#Test
public void testClearSessionsMaintainsSessionsUnlessLastAccessTimeIsOverThreshold() {
final String sessionId = "test";
final Clock mockClock = mock(Clock.class);
when(mockClock.getCurrentDateTime()).thenReturn(getNow());
SessionManager sessionMgr = getSessionManager(connMgr,
sessionGen, factory, mockClock);
createSession(sessionMgr, sessionId);
sessionMgr.clearSessions(defaultTimeout);
assertNotNull(sessionMgr.getSession(sessionId));
when(mockClock.getCurrentDateTime()).thenReturn(getExpired());
sessionMgr.clearSessions(defaultTimeout);
assertNull(sessionMgr.getSession(sessionId));
}
This ran great, but my removal of the Session.setAccessTime() created an issue with another test testOnlyExpiredSessionsCleared() where I wanted one session to expire but not the other. This link https://stackoverflow.com/a/6060814/1258214 led me to thinking about the design of the SessionManager.clearSessions() method, and I refactored the checking if a session is expired from the SessionManager, to the DBSession object itself.
From:
if (session.getAccessTime().before(cal.getTime())) {
To:
if (session.isExpired(expireTime)) {
Then I inserted a mockSession object (similar to Jayan's suggestion https://stackoverflow.com/a/10023916/1258214)
#Test
public void testOnlyOldSessionsCleared() {
final String sessionId = "test";
final String sessionId2 = "test2";
ObjectFactory mockFactory = spy(factory);
SessionManager sm = factory.createSessionManager(connMgr, sessionGen,
mockFactory, clock);
// create expired session
NPIISession session = factory.createNPIISession(null, clock);
NPIISession mockSession = spy(session);
// return session expired
doReturn(true).when(mockSession).isExpired((DateTime) anyObject());
// get factory to return mockSession to sessionManager
doReturn(mockSession).when(mockFactory).createDBSession(
(Connection) anyObject(), eq(clock));
createSession(sm, sessionId);
// reset factory so return normal session
reset(mockFactory);
createSession(sm, sessionId2);
assertNotNull(sm.getSession(sessionId));
assertNotNull(sm.getSession(sessionId2));
sm.clearSessions(defaultTimeout);
assertNull(sm.getSession(sessionId));
assertNotNull(sm.getSession(sessionId2));
}
Thanks to everyone for their help with this. Please let me know if you see any issues with the changes.

Does mockito have an equivalent idiom to jMock's States?

The book Growing Object Oriented Software gives several examples in jMock where the state is made explicit without exposing it through an API. I really like this idea. Is there a way to do this in Mockito?
Here's one example from the book
public class SniperLauncherTest {
private final States auctionState = context.states("auction state")
.startsAs("not joined");
#Test public void addsNewSniperToCollectorAndThenJoinsAuction() {
final String itemId = "item 123";
context.checking(new Expectations() {{
allowing(auctionHouse).auctionFor(itemId); will(returnValue(auction));
oneOf(sniperCollector).addSniper(with(sniperForItem(item)));
when(auctionState.is("not joined"));
oneOf(auction).addAuctionEventListener(with(sniperForItem(itemId)));
when(auctionState.is("not joined"));
one(auction).join(); then(auctionState.is("joined"));
}});
launcher.joinAuction(itemId);
}
}
I used a spy for the self same exercise:
http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#13
I changed my SniperListener mock into a spy thus:
private final SniperListener sniperListenerSpy = spy(new SniperListenerStub());
private final AuctionSniper sniper = new AuctionSniper(auction, sniperListenerSpy);
And also created a stubbed implementation of SniperListener:
private class SniperListenerStub implements SniperListener {
#Override
public void sniperLost() {
}
#Override
public void sniperBidding() {
sniperState = SniperState.bidding;
}
#Override
public void sniperWinning() {
}
}
The book uses JMock's "States", but I used a nested enum instead:
private SniperState sniperState = SniperState.idle;
private enum SniperState {
idle, winning, bidding
}
You then have to use regular JUnit asserts to test for the state:
#Test
public void reportsLostIfAuctionClosesWhenBidding() {
sniper.currentPrice(123, 45, PriceSource.FromOtherBidder);
sniper.auctionClosed();
verify(sniperListenerSpy, atLeastOnce()).sniperLost();
assertEquals(SniperState.bidding, sniperState);
}
Not that I'm aware of. I've used mockito a far amount and there's nothing in the doco similar to what I read on the JMock site about states. If I have it correctly they basically limit the time at which an exepection can occur to the duration of a specific state of another object. It's an interesting idea, but I'm struggling to see the applications for it.
In Mockito you can execute code using Stubbing with callbacks to do the same job. In the callback method you can execute further validations of the state. Alternatively you can employ a Custom argument matcher as they are also executed at the time of the call.
Both of these give you access to the code at execution time which is the time you want to check the state.

Categories