Mockito Unit tests - Timestamps are different - java

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!!

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);
}

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".

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();
}````

Related

How to replace a JSON String with Java?

In my JSON Array inside of its file, it has an array set that goes as follows:
{
"user_interface_fields" : {
"tip_identifier" : {
"uuid": "12345678-1234-1234-1234-123456789112"
}
"insert_time" : "2001-01-01T00:00:00Z"
}
And now I got this file written in java
#Test
public void testExampleMessageToJson() throws Throwable {
log.info("\n\nTesting persist service [message to json]?\n");
//Setup
String rawJson = TestUtils.getResourceMessage("examples/life.json");
String tip_identifier_uuid = "12345678-1234-1234-1234-123456789112";
log.info("Raw Json:\n():", rawJson);
assertTrue(StringUtils.isNotBlank(rawJson));
//Test
JSONObject foundObj = persistService.messageToJson(rawJson);
//Verify
String tip_identifier_time = foundObj.getString("insert_time");
String new_time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(Calendar.getInstance().getTime());
foundObj.put(new_time, foundObj).getString("insert_time");\
assertNotNull(foundObj);
String new_uuid = foundObj.getJSONObject("user_interface_fields").getJSONObject("tip_identifier").getString("uuid");
assertEquals(tip_identifier_uuid , new_uuid);
assertEquals(tip_identifier_time, new_time);
log.info("\n\nTesting persist service [message to json] COMPLETE!\n");
}
My goal is to have life.json's time to be nearly identical to our current time (so like if it's 11/11/21 01:30:21.22, insert_time's data should be around 01:30:21.2234 or whatever and at any time i or any other person runs the code it should be a near match..)
But in my failure trace it tells me:
org.junit.ComparisonFailure: expected:<202[0-02-19'T'00:00:]00> but was:<202[1-11T17:46:46+00]00>
I'm thinking that the logging is messed up because expected should be nearly matched as the current time (as stated in my goal). Since messagetoJson gets the current time and inserts it, when my test pulls out the insert_time it should be a couple of milliseconds behind and so I need to validate that it's within a second or ~1000 milliseconds.
But I don't know what the heck I should do or where I should go from here in order to fix that.

How can I run a function multiple times with multiple data sets or values?

I'm kinda new to programming and got this as an assignment at work. I need to run a method that sends a message (FIX format) multiple times with multiple data sets. Here's how I build with its respective data and send the message:
private void testCaseAttempt(String testCaseName) throws Exception {
StringBuilder errorBuilder = new StringBuilder();
// Read test case arguments
new Arguments(testCaseName);
QuoteRequestBuilder builder = app.builders().quoteRequest();
BigDecimal b1;
b1 = new BigDecimal(10000);
//Date transactTime;
//transactTime = new Date(0);
//expireTime 10 minutes from now
Calendar now = Calendar.getInstance();
now.add(Calendar.MINUTE, 10);
Date expireTime = now.getTime();
//BUILD THE MESSAGE
builder
.setField(131, "5EB26EAAC074000D0000")
.symbol("DANBNK")
.securityID("SE0011116474")
.currency("SEK")
.securityIDSource("4")
.setField(54, "2")
.expireTime(expireTime)
.orderQty(b1)
.setField(64, "20200508")
.setField(1629, "10")
.setField(1916, "0")
.setField(60, "20200526-15:48:53.006")
.setField(761, "1")
.partyID("13585922", PartyIDSource.PROPRIETARY_CUSTOM_CODE, 11, null)
.partyID("1270", PartyIDSource.PROPRIETARY_CUSTOM_CODE, 13, null)
.partyID("SEB", PartyIDSource.PROPRIETARY_CUSTOM_CODE, 1, null)
.partyID("1786343", PartyIDSource.PROPRIETARY_CUSTOM_CODE, 117, null);
Message quoteRequestMessage = builder.getMessage();
//SEND THE MESSAGE
app.sendMessage(quoteRequestMessage, app.getSession(session));
long timeout = Properties.getLong(0L, "waitForMessage", "FIX");
Message responseMessage;
}
I build the FIX message with the "setfield" instructions then I just send it. This works just fine except I need to do it 20-30 times (so 20-30 messages) and I need to slightly change the values or parameteres each time.
I have an idea how to do this with cucumber using a feature file with an "Examples" table with my desired data so it calls this method but that feels like overkill at the moment. I was thinking of using an excel file with a table so I can comfortably change the values in each row and just feed it to this function somehow.
By the way, I didn't copy all the code in the function, I just copied the lines in which the msg is built and sent.
Any idea how I can do this? Your replies are much appreciated!
Thanks in advance.
Create your field map and just iterate that field map as below
Map<Integer,String> fieldMap = new HashMap<>();
fieldMap.put(131,"5EB26EAAC074000D0000");
fieldMap.put(54,"2");
fieldMap.put(64,"20200508");
fieldMap.put(1629,"10");
fieldMap.forEach((k,v)->{
builder.setField(k,v)
});

BigQueryIO: Query configured via options, but "Value only available at runtime"

Apache Beam 2.9.0
I have set up a pipeline that pulls data from BigQuery and does a series of transforms on it. The options have a start date attached to them using a ValueProvider:
ValueProvider<String> getStartTime();
void setStartTime(ValueProvider<String> startTime);
I then go to pull the data with BigQueryIO (changing things around a bit for the sake of making it explicit what is going on):
BigQueryIO.read(
(SerializableFunction<SchemaAndRecord, AggregatedRowRecord>)
input -> new BigQueryParser().apply(input.getRecord()))
.withoutValidation()
.withTemplateCompatibility()
.fromQuery(
ValueProvider.NestedValueProvider.of(
opts.getStartTime(),
(SerializableFunction<String, String>)
input -> {
Instant instant = Instant.parse(input);
return String.format(
<large SQL statement with a %s in it>,
String.format(
"%d_%d_%d",
instant.get(ChronoField.YEAR),
instant.get(ChronoField.MONTH_OF_YEAR),
instant.get(ChronoField.DAY_OF_MONTH)));
}))
.withCoder(<coder for AggregatedRowRecords>)
.usingStandardSql()
This is then added to a pipeline normally (p.apply(<above>)).
Now I run it:
--project=<project> \
--tempLocation=<directory> \
--stagingLocation=<directory> \
--network=dataflow \
--subnetwork=<subnetwork> \
--defaultWorkerLogLevel=DEBUG
--appName=<name>
--runner=DirectRunner
This causes the following error:
org.apache.beam.sdk.Pipeline$PipelineExecutionException: java.lang.IllegalStateException: Value only available at runtime, but accessed from a non-runtime context: RuntimeValueProvider{propertyName=startTime, default=null}
at org.apache.beam.runners.direct.DirectRunner$DirectPipelineResult.waitUntilFinish(DirectRunner.java:332)
at org.apache.beam.runners.direct.DirectRunner$DirectPipelineResult.waitUntilFinish(DirectRunner.java:302)
at org.apache.beam.runners.direct.DirectRunner.run(DirectRunner.java:197)
at org.apache.beam.runners.direct.DirectRunner.run(DirectRunner.java:64)
at org.apache.beam.sdk.Pipeline.run(Pipeline.java:313)
at org.apache.beam.sdk.Pipeline.run(Pipeline.java:299)
at <class>.main(<class>.java:<>)
Caused by: java.lang.IllegalStateException: Value only available at runtime, but accessed from a non-runtime context: RuntimeValueProvider{propertyName=startTime, default=null}
at org.apache.beam.sdk.options.ValueProvider$RuntimeValueProvider.get(ValueProvider.java:228)
at org.apache.beam.sdk.options.ValueProvider$NestedValueProvider.get(ValueProvider.java:131)
at org.apache.beam.sdk.io.gcp.bigquery.BigQueryQuerySource.createBasicQueryConfig(BigQueryQuerySource.java:230)
at org.apache.beam.sdk.io.gcp.bigquery.BigQueryQuerySource.dryRunQueryIfNeeded(BigQueryQuerySource.java:175)
at org.apache.beam.sdk.io.gcp.bigquery.BigQueryQuerySource.getTableToExtract(BigQueryQuerySource.java:115)
at org.apache.beam.sdk.io.gcp.bigquery.BigQuerySourceBase.extractFiles(BigQuerySourceBase.java:102)
at org.apache.beam.sdk.io.gcp.bigquery.BigQueryIO$TypedRead$2.processElement(BigQueryIO.java:783)
The use of NestedValueProvider comes from this example on setting up templates:
The user provides a substring for a BigQuery query, such as a specific date. The transform uses the substring to create the full query. Calling .get() returns the full query.
Removing the value provider logic doesn't seem to help, however. Removing the ValueProvider entirely from the withQuery section works fine, but defeats the purpose of being able to set it via options.
The exception explains you the issue, Apache beam first builds the pipeline and the classes and then start to run the data in the pipeline, in this stage, you can't access to options, this is just metadata for building the pipeline.
The way to overcome it is to create a ParDo function/ PTransform, that will get the options you need as parameters in the constructor, then it can access it in its logic.
See example: (my use case, I face the same issue last days)
The pipeline:
HistoryProcessingOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
.as(HistoryProcessingOptions.class);
Pipeline pipeline = Pipeline.create(options);
pipeline.apply(SourceRead.of(options.getSourceBigQueryTable().get(),
options.getSourceBigQueryDataset().get(),
options.getSourceBigQueryProject().get(),
options.getFromDate().get(),
options.getToDate().get()
))
The transformer itself:
public class SourceRead extends PTransform<PBegin, PCollection<TableRow>> {
private String sourceBigQueryTable;
private String sourceBigQueryDataset;
private String sourceBigQueryProject;
private String formDate;
private String toDate;
private static Logger logger = LoggerFactory.getLogger(SourceRead.class);
public SourceRead(String sourceBigQueryTable, String sourceBigQueryDataset, String sourceBigQueryProject, String formDate, String toDate) {
this.sourceBigQueryTable = sourceBigQueryTable;
this.sourceBigQueryDataset = sourceBigQueryDataset;
this.sourceBigQueryProject = sourceBigQueryProject;
this.formDate = formDate;
this.toDate = toDate;
}
public static SourceRead of(String sourceBigQueryTable, String sourceBigQueryDataset, String sourceBigQueryProject, String yearToLoad, String dateToLoad) {
return new SourceRead(sourceBigQueryTable, sourceBigQueryDataset, sourceBigQueryProject, yearToLoad, dateToLoad);
}
#Override
public PCollection<TableRow> expand(PBegin input) {
String query = "SELECT * FROM TABLE_DATE_RANGE([" + sourceBigQueryProject + ":"+sourceBigQueryDataset+"."+sourceBigQueryTable+"],"
+ "TIMESTAMP('" + formDate + "'),"
+ "TIMESTAMP('" + toDate + "'))";
logger.info("query is"+ query);
return input.apply(BigQueryIO.readTableRows()
.fromQuery(query));
}

Selenium test saving screenshots

I currently have a Selenium test that runs through a website on 11 different languages and takes screenshots of each part. The pictures themselves get saved in respective folders like this in a property file
screenshotsEnglish.dir=/screenshots/Languages/English
screenshotsSwedish.dir=/screenshots/Languages/Swedish
What I want to do different is each time a test suite is run, a new base folder is created with the current date stamp followed up with the same structure as before. How can I make this work? I can't hardcode it in the property file obviously because the date will constantly change.
To give a overall better view how it all works
public static Object[][] dp() {
return new Object[][]{
{
"https://example-URL.net/example.php?lang=EN",
"screenshotsEnglish.dir"
},
{
"https://example-URL.net/example.php?lang=SV",
"screenshotsSwedish.dir"
}
};
}
#Test(dataProvider = "dp")
public void t(String url, String directory) {
driver.get(url);
Properties settings = PropertiesLoader.fromResource("settings.properties");
String screenshotDir = settings.getProperty(directory);
screenShooter = new ScreenShooter(driver, screenshotDir, "en");
/*...*/
}
Tests are written in Java with TestNG
I hope I've made myself clear and as always, appreciate all help loads
Why not like this (not tried to compile, just a quick try, so typos are possible):
String screenshotDir = settings.getProperty(directory); //this is what you already have
String date = new SimpleDateFormat("dd-MM-yyyy").format(new Date()); //added: get current date
screenshotDir = screenshotDir + "/" + date; //added: create modified path
new File(screenshotDir).mkdirs(); //added: make the new directory
screenShooter = new ScreenShooter(driver, screenshotDir, "en"); //this is what you already have

Unit Testing MyBatis Handler

I have used mybatis, and as part of this I have needed to write a custom handler object to convert from database TIMESTAMP to Java XMLGregorianCalendar object.
After some testing, the conversion seems to work except it's not returning times correctly.
In order to ensure I get this running correctly and that I have tests to prove what can be converted I was trying to write a junit test to cover the conversion.
In the test, I have the following:
XMLGregorianCalendarHandler handler = new XMLGregorianCalendarHandler();
and I am trying to test that the getResults method using:
assertEquals(expectedDate , handler.getResult(rs, "timestamp"));
However, I'm not sure how to actually "create" a dummy ResultSet object to pass in as the 'rs' object so I can process the test.
Can anyone point me in the right direction please? am I even on the right track as to how I should be testing an object handler for mybatis?
The actual test code is:
#Test
public void testConvertTimestamp() throws SQLException, DatatypeConfigurationException{
String dbTimestamp = "24-APR-14 15.47.44.000000000";
XMLGregorianCalendar expectedDate = null;
GregorianCalendar c = new GregorianCalendar();
c.set(GregorianCalendar.DAY_OF_MONTH, 24);
c.set(GregorianCalendar.MONTH, GregorianCalendar.APRIL);
c.set(GregorianCalendar.YEAR, 2014);
c.set(GregorianCalendar.HOUR_OF_DAY, 15);
c.set(GregorianCalendar.MINUTE, 47);
c.set(GregorianCalendar.SECOND, 44);
c.set(GregorianCalendar.MILLISECOND, 000000000);
expectedDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
ResultSet rs;
assertEquals(expectedDate , handler.getResult(rs, RS_COLUMN_NAME));
}
Use any mock library to create resultset mock. In Mockito this can look like:
ResultSet rs = Mockito.mock(ResultSet.class);
Mockito.when(resultSetMock.next()).thenReturn(true).thenReturn(false);
Mockito.when(resultSetMock.getString(RS_COLUMN_NAME)).thenReturn(dbTimestamp);

Categories

Resources