I'm writing unit test to my business class and I would like to mock LocalDateTime to a specific time according to my test. Here is my function:
private fun isExpired(access: Access): Boolean {
return access.validUntil.isAfter(LocalDateTime.now())
}
How can I mock LocalDateTime.now()?
My suggestion is that you inject a dependency on a Clock and use that in your method. Apologies that I've converted to Java as I'm not too familiar with kotlin.
class ClassToTest {
private final Clock;
public ClassToTest(Clock clock) {
this.clock = clock;
}
private boolean isExpired(Access access) {
return access.validUntil.isAfter(LocalDateTime.now(clock));
}
}
And the test that uses a fixed 'now' would look like:
#Test
void testIsExpired() {
Clock clock = mock(Clock.class);
when(clock.instant()).thenReturn(Instant.ofEpochSecond(1000L));
when(clock.getZone()).thenReturn(ZoneOffset.UTC);
ClassToTest test = new ClassToTest(clock);
assertThat(test.isExpired(access))...
}
You specifically asked about mocking but you could achieve the same with a constant clock:
#Test
void testIsExpired() {
Clock clock = Clock.fixed(Instant.ofEpochSecond(1000L), ZoneOffset.UTC);
ClassToTest test = new ClassToTest(clock);
assertThat(test.isExpired(access))...
}
Your production code would inject whichever clock you want (such as a particular TZ, local TZ, clocks that tick each second etc.) which are all created using static Clock methods. The ability to change clocks is often a useful feature to have on top of its value for testing.
Related
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()));
}
I am new to writing tests in java, and seem to be unable to test if a method of a class is called.
I am sending metrics to datadog, and want to test in the code if a function of another class was called.
It says I need to mock first, but I couldn't get it to work.
MetricRecorder.java
import com.timgroup.statsd.StatsDClient;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.google.common.base.Preconditions;
public class MetricRecorder {
private final String namespace;
private final static StatsDClient metrics = new NonBlockingStatsDClient(
"my.prefix",
"localhost",
8125,
new String[] {"tag:value"}
);
public MetricRecorder(String namespace) {
Preconditions.checkNotNull(namespace);
this.namespace = namespace;
}
public void inc(String metricName) {
this.inc(metricName, 1);
}
public void inc(final String metricName, final long value) {
Preconditions.checkNotNull(metricName);
try {
metrics.recordHistogramValue(MetricRecorder.name(namespace, metricName), value);
} catch (Exception e) {
logger.warn("Unable to record metric {} due to :", metricName, e);
}
}
...
}
MetricRecorderTest.java
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
MetricRecorder recorder = new MetricRecorder("dev");
recorder.inc("foo", 1);
verify(recorder.metrics, times(1)).recordHistogramValue(eq("dev.foo"), 1);
}
}
When I run the test I get this => org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type NonBlockingStatsDClient and is not a mock!
Any idea of how I should be testing if recordHistogramValue was called, and if so with what arguments?
Since it looks like StatsDClient is an interface of some kind, it would make your testing effort easier to simply inject this dependency into your object. Even if you're not using an IoC container like Spring or Guice, you can still somewhat control this simply by passing an instance of it in through the constructor.
public MetricRecorder(String namespace, StatsDClient client) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(client);
this.namespace = namespace;
this.client = client;
}
This will make your testing simpler since all you realistically need to do is mock the object passed in during test.
Right now, the reason it's failing is because you're newing up the instance, and Mockito (in this current configuration) isn't equipped to mock the newed instance. In all honesty, this set up will make testing simpler to conduct, and you should only need your client configured in one area.
#RunWith(MockitoJUnitRunner.class)
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
StatsDClient dClientMock = Mockito.mock(StatsDClient.class);
MetricRecorder recorder = new MetricRecorder("dev", dClientMock);
recorder.inc("foo", 1);
verify(recorder.metrics).recordHistogramValue(eq("dev.foo"), 1);
}
}
You are getting things wrong here. You don't use a mocking framework to test your "class under test".
You use the mocking framework to create mocked objects; which you then pass to your "class under test" within a test case. Then your "code under test" calls methods on the mocked object; and by controlling returned values (or by verifying what happens to your mock); that is how you write your testcases.
So, your testcase for a MetricRecorder doesn't mock a MetricRecorder; it should mock the StatsDClient class; and as Makoto suggests; use dependency injection to put an object of that class into MetricRecorder.
Besides: basically writing "test-able" code is something that needs to be practiced. I wholeheartedly recommend you to watch these videos if you are serious about getting in this business. All of them; really (worth each second!).
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.
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.
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.