Mocking private method inside a public method - java

I've made a test of a getStudies method, that has a private method call inside itself. Now, how to mock that call in a test method (see down below)?
It's on a second line in a method for testing String query = setQueryForChangingState(filterParams);. I'll provide additional code, if necessary.
Method for testing
public Object getStudies(FilterInputModel filterParams) {
String query = setQueryForChangingState(filterParams);
logger.info("Get studies query: " + query);
LinkedMultiValueMap<String, String> queryMap = new LinkedMultiValueMap<>();
queryMap.add("q", query);
return Objects.requireNonNull(webClient.post()
.uri("/query")
.header(HttpHeaders.AUTHORIZATION, getSessionId())
.body(BodyInserters.fromMultipartData(queryMap))
.retrieve()
.bodyToMono(QueryResponse.class)
.block())
.data;
}
Private method
private String setQueryForChangingState(FilterInputModel filterParams) {
String query = "SELECT id, " +
"basf_study_id__cr.name__v, " +
"name__v, " +
"state__v, " +
"bas_core__cr.name__v, " +
"object_type__vr.name__v, " +
"external__c, " +
"contract_laboratory__cr.name__v, " +
"object_type__v " +
"FROM study__c " +
"WHERE object_type__vr.name__v = 'External Study' " +
"AND contract_laboratory__c != null " +
"AND state__v = 'study_setup_completed_state__c'";
if (!filterParams.getCores().isEmpty()) {
query = query + " AND bas_core__c CONTAINS('" + String.join("','", filterParams.getCores()) + "')";
}
if (!filterParams.getStudyStartDate().isEmpty()) {
if (filterParams.getStudyStartDate().size() == 1) {
query = query + " AND study_start_date__c = '" + filterParams.getStudyStartDate().get(0) + "'";
} else if (filterParams.getStudyStartDate().size() == 2) {
query = query + " AND study_start_date__c BETWEEN '" + filterParams.getStudyStartDate().get(0) + "' AND '" + filterParams.getStudyStartDate().get(1) + "'";
} else {
logger.info("Date range has to many inputs!");
}
}
return query;
}
My test
#Test
#DisplayName("Test getStudies")
void getStudies() throws IOException {
Path filePath = Path.of("src/test/resources/__files/jsonFile.json");
String body = Files.read(filePath.toFile(), Charset.defaultCharset());
wireMockServer.stubFor(post(urlEqualTo("/api/v16.1/query"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody(body))
);
List<String> cores = List.of("core");
List<String> dates = List.of("startDate");
List<String> objectTypes = List.of("objectType");
inputModel = new FilterInputModel(cores,dates, "state",objectTypes,
"area","analytMethod", "wp", "subDesc", "analytMonitor", "ecoMonitor",
"subType", "analytNeeded", "8e6a2", "methodAvailable",
"analytPhase", "subAvailable","subShipped", "external",
"uploadValidator","contractLab");
Object response = vaultServiceTest.getStudies(inputModel);
QueryResponse jsonBody = new ObjectMapper().readValue(body, QueryResponse.class);
assertEquals(response, jsonBody.data);
I guess it could be done, but I'm not sure how.

Related

Testing a weird Service function

I'm testing a Spring Boot Service, and there's one pretty much weird function that needs to be tested. I've made a test that runs successfully, but I'm not getting much coverage. Here's a function I'm testing:
protected String setQueryListField(List<String> model, String fieldName) {
String query = "";
if (model.contains("is blank") && model.size() > 1) {
for (String value : model) {
if (value.equals("is blank")) {
query = query.concat(" AND (" + fieldName + " = null");
} else if (model.size() == 2) {
query = query.concat(" OR " + fieldName + " CONTAINS('" + value + "'))");
} else {
if (model.indexOf(value) == 1) {
query = query.concat(" OR " + fieldName + " CONTAINS('" + value + "', ");
} else if ((model.indexOf(value) + 1) == model.size()) {
query = query.concat("'" + value + "'))");
} else {
query = query.concat("'" + value + "', ");
}
}
}
} else if (model.contains("is blank") && model.size() == 1) {
query = query.concat(" AND " + fieldName + " = null");
} else {
query = query.concat(" AND " + fieldName + " CONTAINS('" + String.join("','", model) + "')");
}
return query;
}
And here is a test I wrote. It runs successfully, as I said, but I'd like to get more coverage. Do you have any suggestions?
#Test
#DisplayName("setQueryListField Test")
void setQueryListField() {
List<String> stringList = new ArrayList<>();
stringList.add("is blank");
VaultService vaultService = Mockito.spy(vaultServiceTest);
doReturn("", "").when(vaultService).setQueryListField(stringList, "field__name");
String response = vaultService.setQueryListField(stringList, "field__name");
System.out.println(response);
stringList.add("test");
String secondResponse = vaultService.setQueryListField(stringList, "external__c");
System.out.println(secondResponse);
}
You are only covering the following if block
else if (model.contains("is blank") && model.size() == 1) {
query = query.concat(" AND " + fieldName + " = null");
}
If you need more coverage you need to try with other inputs so that it covers other branches too. For example, with model.size() > 1.
Also, the following lines are no op as it's mocking the same function that you are trying to test.
VaultService vaultService = Mockito.spy(vaultServiceTest);
doReturn("", "").when(vaultService).setQueryListField(stringList, "field__name");
String response = vaultService.setQueryListField(stringList, "field__name");

Try with resource class variable gets null

protected void saveData() {
Map<String, String> allStationsParams = new HashMap<>();
List<String> stations = getAllStations();
stmt = Database.getUpdateableStatement();
today = (SysTime.currentTimeMillis() / DasStamp.TICKS_PER_DAY) *
DasStamp.TICKS_PER_DAY;
String changeTimestamp = DasStamp.asCompactString(today);
String keyName = "COM.MAPPINGTOOLTIP." + attributeValue;
for (int row = 0; row < this.getTableModel().getRowCount(); row++) {
String station = (String)this.getTableModel().getValueAt(row, 0);
putInStationParams(this, station, allStationsParams, row);
}
for (String station : stations) {
boolean sendToDB = false;
try (ResultSet rs = this.rsParameters) {
rs.beforeFirst();
while (rs.next()) {
if (rs.getString("station").equals(station)) {
sendToDB = true;
break;
}
}
if (sendToDB) {
if (!rs.getString("value_text").equals(allStationsParams.get(station)) || !allStationsParams.containsKey(station)) {
sendToDB = true;
} else {
sendToDB = false;
}
} else if (allStationsParams.containsKey(station)) {
sendToDB = true;
}
if (sendToDB) {
String sql = "REPLACE INTO dss_parameter (key_name, station, valid_from, value_text"
+ ", change_timestamp) VALUES ('"
+ keyName + "','" + station + "','" + DasStamp.asDateOnlyString(today) + "','"
+ Helper.nz(allStationsParams.get(station)) + "','"
+ changeTimestamp + "') ;";
if (null != stmt) {
stmt.execute(sql);
if (!isResultSetEmpty(rs) && !rs.isAfterLast()) {
AdminLogger.log("dss_parameter", Action.UPDATE,
"key_name='" + keyName + "' and station='" + station + "' and valid_from='" + DasStamp.asDateOnlyString(today) + "'",
"value_text='" + rs.getString("value_text") + "'",
"value_text='" + Helper.nz(allStationsParams.get(station)) + "', change_timestamp='" + changeTimestamp + "'");
} else {
AdminLogger.log("dss_parameter", Action.INSERT,
"key_name='" + keyName + "' and station='" + station + "' and valid_from='" + DasStamp.asDateOnlyString(today) + "'",
"", "value_text='" + Helper.nz(allStationsParams.get(station)) + "', change_timestamp='" + changeTimestamp + "'");
}
}
}
} catch (SQLException e) {
AppFrame.msgBox("Error on insert: " + e.getMessage());
Helper.printMessage(true, false, "Parameter save failed!!", e);
}
}
}
where rsParameters is class level and is fetched before. After first
iteration, rsParameters values is getting null.Is this a problem with try
with resource block? Please help
where rsParameters is class level and is fetched before. After first
iteration, rsParameters values is getting null.Is this a problem with try
with resource block? Please help
Your rsParameters parameter is of Type Resultset.
In first iteration, after try{} block is complete close() method of rsParameters:ResultSet is called.
This internally makes all the properties of resultSet NUll.
That is the reason for getting Null properties during second iteration.
SEE: http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.27/com/mysql/jdbc/ResultSetImpl.java#ResultSetImpl.realClose%28boolean%29

Store config data into abstract class or interface

I work in a java library working with database. I want to store the config datas for use them to connection and sql queries.
How can store config data?
It's ok to put them into abstract final class?
public final class MySQLConfig {
final public static String
DRIVER = "com.mysql.jdbc.Driver",
DBURL = "jdbc:mysql://localhost/dbname",
USER = "user",
PASS = "pass",
PREFIX = "vab_",
CARDS_TABLE = "cards",
CARDS_CARD_ID = "card_id",
CARDS_OWNER_ID = "owner_id",
CARDS_LABEL = "label",
CARDS_AMOUNT = "amount",
TRANSACTIONS_TABLE = "transactions",
TRANSACTIONS_TRANSACTION_ID = "transaction_id",
TRANSACTIONS_CARD_ID = "card_id",
TRANSACTIONS_USER_ID = "owner_id",
TRANSACTIONS_DESCRIPTION = "label",
TRANSACTIONS_AMOUNT = "amount",
TRANSACTIONS_DATE = "datetime",
TRANSACTIONS_TYPE = "type",
// Prevent create instance
private MySQLConfig() {
}
}
I use them like this:
public static Connection createConnection() {
try {
Class.forName(MySQLConfig.DRIVER);
return DriverManager.getConnection(MySQLConfig.DBURL, MySQLConfig.USER, MySQLConfig.PASS);
} catch (ClassNotFoundException | SQLException ex) {
}
return null;
}
Or in sql statement:
String sql = "INSERT INTO " + MySQLConfig.PREFIX + MySQLConfig.CARDS_TABLE + " ("
+ MySQLConfig.CARDS_OWNER_ID + ", "
+ MySQLConfig.CARDS_LABEL + ", "
+ MySQLConfig.CARDS_AMOUNT + " "
+ ") "
+ "VALUES ("
+ "'" + String.valueOf(ownerId) + "', "
+ "'" + label + "', "
+ "'" + initAmount.toPlainString() + "'"
+ ")";
How I can store correctly this data?

Display a for loop in my return findSingleOrNoItem() in java

How can I add in my return findSingleOrNoItem() at the end of the statement to display the for loop counter getClassName() and getAbsolutePercentage() in the findSingleOrNoItem() statement? The reason I added a counter, some will have 4 values of getClassName() and getAbsolutePercentage() and some will have 6 values? so this will depend on the cosModel that gets passed on setParameter 1.
#Override
public TrafficProfile getTrafficProfileByCosClassAllocationNew(CosModel cosModel, Direction direction,
List<ClassOfServiceAllocation> cosClassAllocation, RouterType routerType) throws Exception {
EntityManager em = getEntityManager();
logger.info("Starting getTrafficProfileByCosClass2Allocations cos2 " );
Query query = em.createNativeQuery(buildTrafficProfileByCosClassAllocationQueryNew(cosModel, direction, cosClassAllocation, routerType), TrafficProfile.class);
query.setParameter(1, cosModel.name());
query.setParameter(2, direction.name());
int i= 2;
for(ClassOfServiceAllocation alloc : cosClassAllocation){
query.setParameter(i++, alloc.getClassName());
query.setParameter(i++, alloc.getAbsolutePercentage());
}
return findSingleOrNoItem(query, "Traffic_Profile", "cos_model = " + cosModel.name() + ", direction = " + direction.name() + ?;
}
I am following this existing code below but this is only for cos6. I will have both cos4 and cos6 so I can't hard coded.
#Override
public TrafficProfile getTrafficProfileByCosClassAllocations(Direction direction,
ClassOfService6Allocations cosClassAllocation, RouterType routerType) throws Exception {
EntityManager em = getEntityManager();
logger.info("Starting getTrafficProfileByCosClass6Allocations cos6" );
Query query = em.createNativeQuery(buildTrafficProfileByCosClassAllocationsQuery(direction, cosClassAllocation, routerType), TrafficProfile.class);
query.setParameter(1, "cos6");
query.setParameter(2, direction.name());
query.setParameter(3, cosClassAllocation.getCos1());
query.setParameter(4, cosClassAllocation.getCos2V());
query.setParameter(5, cosClassAllocation.getCos2());
query.setParameter(6, cosClassAllocation.getCos3());
query.setParameter(7, cosClassAllocation.getCos4());
query.setParameter(8, cosClassAllocation.getCos5());
return findSingleOrNoItem(query, "Traffic_Profile", "cos_model = cos6, direction = " + direction.name() + " cos1 = " + cosClassAllocation.getCos1()
+ " cos2v = " + cosClassAllocation.getCos2V() + " cos2 = " + cosClassAllocation.getCos2()
+ " cos3 = " + cosClassAllocation.getCos3() + " cos4 = " + cosClassAllocation.getCos4() + " cos5 = " + cosClassAllocation.getCos5() );
}
Assuming that your ClassOfService6Allocations and supposedly ClassOfService4Allocations inherit from ClassOfServiceAllocation you can check, inside your for-loop, what is the type of the current object and then cast to this class, for instance:
for(ClassOfServiceAllocation alloc : cosClassAllocation) {
if (alloc instanceof ClassOfService6Allocations) {
ClassOfService6Allocations alloc6 = (ClassOfService6Allocations) alloc;
//set your parameters using the alloc6 object
} else if (alloc instanceof ClassOfService4Allocations) {
ClassOfService4Allocations alloc4 = (ClassOfService4Allocations) alloc;
//set your parameters using the alloc4 object
}

Jena sparql (Dbpedia) query OPTIONAL filter gives no results but (http://dbpedia.org/snorql/) same query works

hello ive this query in this site working http://dbpedia.org/snorql/
PREFIX ontology: <http://dbpedia.org/ontology/>
SELECT DISTINCT ?author ?name ?wiki ?desc ?thumb WHERE {
?author a ontology:Book;
rdfs:label ?name;
ontology:wikiPageID ?wiki;
ontology:abstract ?desc.
OPTIONAL {?author <http://dbpedia.org/ontology/thumbnail> ?thumb }.
FILTER (lang(?name) = 'en')
FILTER (regex(?name, "lo") || regex(?desc, "lo"))
FILTER (lang(?desc) = 'en').
}ORDER BY ?name LIMIT 100
but in my jena queryFactory java class it only works if i remove Optional filter for thumbnail at this line :
OPTIONAL {?author <http://dbpedia.org/ontology/thumbnail> ?thumb }.
here is my jena java method that works :
private String authorQuery(String entity, String keyWord, String language) {
return addPrefix("rdfs: <http://www.w3.org/2000/01/rdf-schema#>") +
addPrefix("rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>") +
addPrefix("dbpprop: <http://dbpedia.org/property/>") +
addPrefix("ontology: <http://dbpedia.org/ontology/>") +
addQuery("SELECT DISTINCT ?author ?name ?wiki ?desc ?thumb WHERE {\n" +
"?author a ontology:" + entity + ";\n" +
"rdfs:label ?name;\n" +
"ontology:wikiPageID ?wiki;\n" +
"ontology:abstract ?desc;\n" +
"<http://dbpedia.org/ontology/thumbnail> ?thumb.\n" +
"FILTER (lang(?name) = '" + language + "') " +
"FILTER (regex(?name, \"" + keyWord + "\") || regex(?desc, \"" + keyWord + "\"))\n" +
" FILTER (lang(?desc) = '" + language + "')." +
"}\n" +
"ORDER BY ?name\n" +
"LIMIT 40000");
}
but as soon as i add optionnal keyword in this line :
"<http://dbpedia.org/ontology/thumbnail> ?thumb.\n" +
No result are returned, can someone tell me why? :(
PS : it work well without OPTIONAL FILTER
Edit : whole DbpediaQuery class
public class DbPediaQuery {
//array of authors
private DbPediaQuery() {
}
public static DbPediaQuery createDbPediaQuery() {
return new DbPediaQuery();
}
public LinkedList<Entity> queryAuthor(String entity, String keyWord, String language) {
LinkedList<Entity> temp = new LinkedList<>();
Query query = QueryFactory.create(authorQuery(entity, keyWord, language));
QueryExecution qexec = QueryExecutionFactory.sparqlService("http://dbpedia.org/sparql", query);
try {
temp.addAll(collectAuthors(qexec.execSelect()));
} catch (Exception e) {
e.printStackTrace();
}
return temp;
}
private String authorQuery(String entity, String keyWord, String language) {
return addPrefix("rdfs: <http://www.w3.org/2000/01/rdf-schema#>") +
addPrefix("rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>") +
addPrefix("dbpprop: <http://dbpedia.org/property/>") +
addPrefix("ontology: <http://dbpedia.org/ontology/>") +
addQuery("SELECT DISTINCT ?author ?name ?wiki ?desc ?thumb WHERE {\n" +
"?author a ontology:" + entity + ";\n" +
"rdfs:label ?name;\n" +
"ontology:wikiPageID ?wiki;\n" +
"ontology:abstract ?desc;\n" +
"<http://dbpedia.org/ontology/thumbnail> ?thumb.\n" +
"FILTER (lang(?name) = '" + language + "') " +
"FILTER (regex(?name, \"" + keyWord + "\") || regex(?desc, \"" + keyWord + "\"))\n" +
" FILTER (lang(?desc) = '" + language + "')." +
"}\n" +
"ORDER BY ?name\n" +
"LIMIT 40000");
}
private LinkedList<Entity> collectAuthors(ResultSet results) {
LinkedList<Entity> temp = new LinkedList<>();
while (results.hasNext()) {
Entity a = new Entity();
QuerySolution row = results.next();
String fullName = row.get("name").toString().substring(0, row.get("name").toString().indexOf("#"));
String biography = row.get("desc").toString().substring(0, row.get("desc").toString().indexOf("#"));
a.setTitle(fullName);
a.setWikiID(Integer.parseInt(row.get("wiki").toString().substring(0, row.get("wiki").toString().indexOf("^"))));
if (!row.get("thumb").toString().isEmpty())
a.setPictureURL(row.get("thumb").toString());
else
a.setPictureURL("http://www.google.fr/imgres?imgurl=http%3A%2F%2Fwww.elated.com%2Fres%2FImage%2Farticles%2Fmanagement%2Fapache%2Fmaking-a-custom-error-page%2Fapache_404_default.gif&imgrefurl=https%3A%2F%2Fgithub.com%2Fjdorn%2Fphp-reports%2Fissues%2F43&h=241&w=400&tbnid=KQI5AbkkVp3-uM%3A&zoom=1&docid=6Bd7CTaQ291_UM&ei=5AU0VceoI87WPYOvgCg&tbm=isch&iact=rc&uact=3&dur=3255&page=1&start=0&ndsp=20&ved=0CDYQrQMwBw");
a.setBiography(biography);
temp.add(a);
System.out.println("FAAT" + a.getTitle());
}
return temp;
}
private String addPrefix(String prefix) { return "PREFIX " + prefix + "\n"; }
private String addQuery(String query) { return query; }
}
ok i figured it out after logging several things... First ive loged the resultset size, with the optional filter it gave me more results than if i put no optional filter... 2383 vs 2103(without optional).. then i noticied that if
a.setPictureURL(row.get("thumb2").toString()); is empty or null the loop dont continue... it stoped after 14 results and gave me no return for this method :
private LinkedList<Entity> collectAuthors(ResultSet results) {
LinkedList<Entity> temp = new LinkedList<>();
while (results.hasNext()) {
Entity a = new Entity();
QuerySolution row = results.next();
String fullName = row.get("name").toString().substring(0, row.get("name").toString().indexOf("#"));
String biography = row.get("desc").toString().substring(0, row.get("desc").toString().indexOf("#"));
a.setTitle(fullName);
a.setWikiID(Integer.parseInt(row.get("wiki").toString().substring(0, row.get("wiki").toString().indexOf("^"))));
if (!row.get("thumb").toString().isEmpty())
a.setPictureURL(row.get("thumb").toString());
a.setBiography(biography);
temp.add(a);
System.out.println("FAAT" + a.getTitle());
}
return temp;
}
so i just checked with if(row.getResource("thumb2")!=null) like that
if(row.getResource("thumb")!=null)
a.setPictureURL(row.get("thumb").toString());
and then the loop continued ---> problem solved
Thanks everyone for your hints and be carefull of empty reslutset columns with Jena

Categories