Reputation: 1181
Having some issues with a Mockito test.
I currently get this error:
Argument(s) are different! Wanted:
repository.save(
uk.co.withersoft.docservice.repositories.hibernate.MetaDataEntity@3e437e6c
);
-> at uk.co.withersoft.docservice.datastore.impl.MetaDataStoreImplTest.storeClaimMetadata(MetaDataStoreImplTest.java:55)
Actual invocation has different arguments:
repository.save(
uk.co.withersoft.docservice.repositories.hibernate.MetaDataEntity@3e361ee2
);
I'm pretty sure its because the times within MetaDataEntity
are different
//This is what I should be getting
id = null
metaData = "{"caseReference":"CN00000001","claimReference":"LN00000001","rpsDocumentType":"REJ","documentTitle":"Claims LN00000001 (Claimant: Mr LOCAL HOST) REJ-Rejection letter"}"
batchId = 0
state = "Saved MetaData to DB"
lastUpdatedDate = {Timestamp@1517} "2018-07-25 18:39:21.993"
createdDate = {Timestamp@1518} "2018-07-25 18:39:21.993"
// This is actually what I get.
id = null
metaData = "{"caseReference":"CN00000001","claimReference":"LN00000001","rpsDocumentType":"REJ","documentTitle":"Claims LN00000001 (Claimant: Mr LOCAL HOST) REJ-Rejection letter"}"
batchId = 0
state = "Saved MetaData to DB"
lastUpdatedDate = {Timestamp@1530} "2018-07-25 18:39:49.274"
createdDate = {Timestamp@1531} "2018-07-25 18:39:52.716"
Here is my test case:
@Test
public void storeClaimMetadata () throws JsonProcessingException {
ClaimMetaData metaData = constructMetaData();
MetaDataEntity mockResponseMetaDataEntity = new MetaDataEntity();
mockResponseMetaDataEntity.setId(1);
when(repository.save(any(MetaDataEntity.class))).thenReturn(mockResponseMetaDataEntity);
Integer result = testSubject.storeClaimMetadata(metaData);
assertEquals(Integer.valueOf(1), result);
final ObjectMapper mapper = new ObjectMapper();
String jsonMetaData = mapper.writeValueAsString(metaData);
MetaDataEntity expectedMetaDataEntity = new MetaDataEntity(null,
jsonMetaData,
0,
"Saved MetaData to DB",
new Timestamp(System.currentTimeMillis()),
new Timestamp(System.currentTimeMillis()));
Mockito.verify(repository, times(1)).save(expectedMetaDataEntity);
}
//Creates a ClaimRequest
private ClaimMetaData constructMetaData() {
final ClaimMetaData metaData = new ClaimMetaData("CN00000001",
"LN00000001",
"REJ",
"Claims LN00000001 (Claimant: Mr LOCAL HOST) REJ-Rejection letter");
return metaData;
}
Any help would be much appreciated. This has been driving me crazy!!
Upvotes: 5
Views: 13817
Reputation: 96394
This is exactly why people use dependency injection, so they can specify test collaborators that give back predictable results. Replace the hardcoded new Timestamp(System.currentTimeMillis)
stuff with calls to Timestamp.from(Instant.now(clock))
.
java.time.Clock
is an interface that you can use to get your timestamp values. The real implementation can be injected into the code being tested, using one of the factory methods that returns a system clock, like this (using Spring Java configuration):
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
and for the test code you can have an implementation where you specify the time you want the clock to return:
@Before
public void setUp() {
clock = Clock.fixed(date.toInstant(), ZoneId.of("America/NewYork"));
systemUnderTest.setClock(clock);
}
Upvotes: 7
Reputation: 41
In Code , instead of using new Timestamp(System.currentTimeMillis())
, you can use
new Timestamp(DateTimeUtils.currentTimeMillis())
. Here DateTimeUtils is from jodatime.
In test cases, can use below.
private SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss:SSS");
@Before
public void before() throws Exception {
// define a fixed date-time
Date fixedDateTime = DATE_FORMATTER.parse("01/07/2016 16:45:00:000");
DateTimeUtils.setCurrentMillisFixed(fixedDateTime.getTime());
}
@After
public void after() throws Exception {
// Make sure to cleanup afterwards
DateTimeUtils.setCurrentMillisSystem();
}````
Upvotes: 1
Reputation: 140467
This is "works as designed".
You are invoking a service that computes timestamps. Like, now.
Then you have a test case that has some setup going on, and fetches time stamps, too. Now.
Guess what: albeit these two "nows above are close to each other, there is still a bit of delay between them.
You are checking for equality, can only work when the time stamps are identical! But they aren't, because they are created one after the other, with very well noticeable delays in between!
Meaning: you need to look how you could control which timestamps are created within your application, like saying "the timestamps should be t1 and t2". So that your test can then check "I found t1 and t2".
Alternatively, you simply change your verification step: instead of trying to have "equal" objects (that can't be equal because different time stamps!), you could compare those parts that should be equal, and for the time stamps, you could check that they are "close enough".
Upvotes: 3