I am writing unit tests for he below code. but coverage is missing for the below lines of code. I am not sure how can we cover the below lines.My research didnt help.
public DetailsResponse mapRow(ResultSet resultSet, int num) throws SQLException {
DetailsResponse DetailsResponse = new DetailsResponse();
String[] responseElements = null;
String response = resultSet.getString(1);
//coverage missing for below line
if (response != null && response.indexOf(",") != -1) {
responseElements = response.split(",");
}
//coverage missing for below line
if (responseElements != null && responseElements.length > 0) {
//coverage missing for below line
String id = StringUtils.isNotBlank(responseElements[0]) ? responseElements[0].replace("(", "") : "";
The commented lines are missing from the coverage., how can i test them?
Since this is a public method and you are trying to write a unit test, not an integration test, you can simply setup a ResultSet object. In doing so, you can set the object so that both conditions will get covered.
#Test
public void test(){
// SETUP
ResultSet resultSet = // setup ResultSet to return what looks like a comma separated list.
// TEST
DetailsResponse out = service. mapRow(resultSet, someNum);
// VERIFY / ASSERT
// some assert(s) on out
}
Related
Untested code (just thinking out loud), but I'm thinking there must be a more elegant way to do this.
So there's three ways to set a variable:
just assign it
read it from a properties file (might not be there)
read it from the command line (could be more than one argument or none)
Higher number takes precedence. How would I approach this?
public static final String APP_DOWNLOAD_PATH;
[...]
// If download path is not defined in config.properties, set it to the app dir.
String download = properties.getProperty("download", System.getProperty("user.dir"));
// Override if download path is set via command line.
String override = null;
try {
override = System.getProperty("download");
} catch (NullPointerException | IllegalArgumentException ok) {
// property is either not found or empty.
}
String APP_DOWNLOAD_PATH = (override == null || override.isEmpty()) ? download : override;
E: Added restrictions.
The straight forward approach is the best in my opinion. For example:
public static final String APP_DOWNLOAD_PATH = "foo";
public static void main(String... args) {
String dwnPath = null;
if(args.length > 0) {
dwnPath = args[0];
} else if(System.getProperty("download") != null) { // don't need try-catch, "download" is not null and not empty ("")
// not DRY at all
dwnPath = System.getProperty("download");
} else {
dwnPath = APP_DOWNLOAD_PATH;
}
// rest of program
}
The above could also be extracted to it's own function leading to a one liner:
String dwnPath = getDownloadPath(args, System.getProperty("download"), APP_DOWNLOAD_PATH);
The extracted function can also be more elegant than the code above:
/** Documentation */
public static String getDownloadPath(String[] args, String property, String default) {
return (args.length > 0) ? args[0] : (property != null) ? property : default;
}
If it is ok to use a external library, then this apache commons method could be useful -
StringUtils.firstNonEmpty(System.getProperty("download"),
properties.getProperty("download", System.getProperty("user.dir")),
"some value");
I'm writing a junit test case for a method in the data access layer, how to stub/verify a complex query using mockito?
checked the following links on how to stub a complex query:
- https://howtodoinjava.com/hibernate/hibernate-criteria-queries-tutorial/
- https://github.com/MorphiaOrg/morphia/issues/933
none of them match my case, and the documentation does not say much about it
https://static.javadoc.io/org.mockito/mockito-core/2.8.9/index.html?org/mockito/Mockito.html
Actual code :
public List<Content> getContentByParams(String entity, String channelId, String sectionId,
Integer limit, String[] retrievedFields) {
Query<Content> query = this.createQuery();
if (StringUtils.isNotBlank(channelId) && StringUtils.isNotBlank(sectionId)) {
query.and(query.criteria("name").equalIgnoreCase(entity),
query.criteria("channel").equal(channelId),
query.criteria("section").equal(sectionId));
System.out.println("after===============");
}
if (retrievedFields != null && retrievedFields.length > 0) {
System.out.println("retrieved fields");
for (String field : retrievedFields) {
query.project(field, true);
}
}
if (limit == null) {
limit = 4;
}
FindOptions findOptions = new FindOptions().limit(limit);
return query.asList(findOptions);
}
Test case :
public void getContentByEntitiesAndPrimaryChannelSection() {
FieldEnd<Criteria> mockFieldEndEntity = mock(FieldEnd.class);
FieldEnd<Criteria> mockFieldEndChannel = mock(FieldEnd.class);
FieldEnd<Criteria> mockFieldEndSection = mock(FieldEnd.class);
// doReturn(mockFieldEndEntity).when(query).criteria("name");
// doReturn(mockFieldEndChannel).when(query).criteria("channel");
// doReturn(mockFieldEndSection).when(query).criteria("section");
contentDAO.getContentByParams(entity, "channel_3", "section_3", 10, mockFields);
for (String field : mockFields) {
verify(query).project(field, true);
}
ArgumentCaptor<FindOptions> argument = ArgumentCaptor.forClass(FindOptions.class);
verify(query).asList(argument.capture());
FindOptions findOptions = argument.getValue();
assertEquals(10, findOptions.getLimit());
PowerMockito.verifyStatic(MongoQueryUtil.class, times(1));
}
I am unsure on how to add a test for the query creation part with the test current status it passes but it is not testing the query creation.
any help will be appreciated or if there is a documentation for it somewhere.
I am working on a school assignment that required us to use SQL statements in Java code as well as use the LIKE operator for a search. In order to properly search I have to get a string from the user, and split the string by any delimiter, and then run the query like so:
SELECT * FROM movies WHERE (movies.title LIKE '%userInput%');
I then return this query in the form of an ArrayList.
Now, when I was testing it out. I originally tested it with no user input, and my query became: SELECT * FROM movies WHERE (movies.title LIKE '%%');. This gave me the correct results.
However when I put a title in there, all of the sudden I get a NullPointerException on this line:
if(title.equals("")) { return "(movies.title LIKE '%%') "; from this section of my code:
public String getSearchString(String title) {
if(title.equals("")) { return "(movies.title LIKE '%%') "; }
String ret = "(";
ArrayList<String> titleArray = Util.splitSearch(title);
for(int i = 0; i < titleArray.size() - 1; ++i) {
String temp = titleArray.get(i);
String stmt = "movies.title LIKE '%" + temp + "%' OR ";
ret += stmt;
}
String temp = "movies.title LIKE '%" + titleArray.get(titleArray.size() - 1) + "%')";
ret += temp;
return ret;
}
This is then called like so:
public List<Movie> listMovies(String title) throws SQLException {
List<Movie> search = new ArrayList<Movie>();
if(null != title && title.isEmpty()) { title = ""; }
ResultSet res = queryMovies(getSearchString(title));
while(res.next()) {
Movie mov = new Movie();
mov.setTitle(res.getString("title"));
search.add(mov);
}
return search;
}
private static queryMovies(String st) throws SQLException {
ResultSet res = null;
try {
PreparedStatement ps = dbcon.prepareStatement(st);
res = ps.executeQuery();
} catch(SQLException e) {
e.printStackTrace();
}
return res;
}
I unfortunately have to do this since I won't know how much a user will enter. And I am also not allowed to use external libraries that make the formatting easier. For reference my Util.splitSearch(...) method looks like this. It should be retrieving anything that is a alphanumeric character and should be splitting on anything that is not alphanumeric:
public static ArrayList<String> splitSearch(String str) {
String[] strArray = str.split("[^a-zA-Z0-9']");
return new ArrayList(Arrays.asList(strArray));
}
What is interesting is when I pass in getSearchString(""); explicitly, I do not get a NullPointerException. It is only when I allows the variable title to be used do I get one. And I still get one when no string is entered.
Am I splitting the String wrong? Am I somehow giving SQL the wrong statement? Any help would be appreciated, as I am very new to this.
the "title" which is passed from input is null, hence you're getting nullpointerexception when you do title.equals("").
Best practices suggest you do a null check like (null != title && title.equals("")).
You can also do "".equals(title)
I'm dealing with an Oracle 10g database and the following stored procedure is provided:
procedure get_synopsis (
p_id in my_schema.products.p_id%type,
p_synopses out sys_refcursor); -- cursor of - synopsis_type, synopsis_text
In my Java code I prepare the statement in this way:
String idForDb = fromIdUrlToIdDb(prodIdUrl);
statement.registerOutParameter(1, OracleTypes.VARCHAR);
statement.setString(1, idForDb );
statement.registerOutParameter(2, OracleTypes.CURSOR);
And I get the data I need in this way:
String defaultSyn, nonDefSyn;
String returnedId = ((OracleCallableStatement)stm).getString(1);
try ( ResultSet synopses = ((OracleCallableStatement)stm).getCursor(2) ){ // p_synopses - cursor of: synopsis_type, synopsis_text
while( synopses!=null && synopses.next() ){
String type = synopses.getString(1) != null ? synopses.getString(1).toUpperCase() : null;
if( type != null ){
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader( synopses.getClob(2).getCharacterStream() );
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
if("DEFAULT".equals(type)){
defaultSyn = sb.toString();
}else if("NONDEFAULT".equals(type)){
nonDefSyn = sb.toString();
}
// ...
}
}
}
In my tests how can I mock (OracleCallableStatement)stm.getCursor(2)?
I'm trying with org.jmock.Mockery but without success:
Mockery mockery_inner = new Mockery();
final ResultSet mocked_resultset = mockery_inner.mock(ResultSet.class);
mockery_inner.checking(new Expectations() {{
allowing(mocked_resultset).getString(1); will(returnValue("TEST_SYNOPSES-TYPE"));
allowing(mocked_resultset).getClob(2); will(returnValue("TEST_CLOooooooB"));
}});
Mockery mockery = new Mockery();
final CallableStatement statement = mockery.mock(CallableStatement.class);
mockery.checking(new Expectations() {{
allowing(statement).getString(1); will(returnValue("TEST_RETURNED-PROD-ID"));
allowing(statement).getCursor(2); will(returnValue(mocked_resultset)); // cannot find symbol getCursor(int). Location: interface java.sql.CallableStatement
}});
Reason clearly is: cannot find symbol getCursor(int). Location: interface java.sql.CallableStatement.
If I try allowing((OracleCallableStatement)statement).getCursor(2) I get "java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to oracle.jdbc.driver.OracleCallableStatement". Note: OracleCallableStatement is not an interface and thus cannot be mocked with Mockery.
I'm trying to use a "manual" mock but I'm having problems creating an instance..
class MockOracleCallableStatement implements OracleCallableStatement {
ResultSet mocked_resultset;
public MockOracleCallableStatement(){
Mockery mockery_inner = new Mockery();
mocked_resultset = mockery_inner.mock(ResultSet.class);
mockery_inner.checking(new Expectations() {{
allowing(mocked_resultset).getString(1); will(returnValue("DEFAULT")); // will pick value from an array
allowing(mocked_resultset).getClob(2); will(returnValue("TEST_CLOooooooooooB"));
}});
}
#Override
ResultSet getCursor(int paramIndex) throws SQLException{
return mocked_resultset;
}
#Override
String getString(int paramIndex) throws SQLException{
return "mockedGetString1--test";
}
}
In a nutshell, DON'T.
Mocking JDBC (along with a lot of other things) is a fools errand and will not test the things you think it's testing but will cost you a huge amount of time.
You should really write an integration test that actually goes to your database. This is the only way to verify your database code is correct. If you can, use the exact same version of the database as you do in production, if not use an in-memory database like H2*.
I wrote an article for JAX magazine on this exact subject which will go into much more detail.
Although this has other issues due to compatibility
It seems like I can use Mockito..
OracleCallableStatement oraCSMock = Mockito.mock(OracleCallableStatement.class);
UPDATE:
The method CLOB.getDBAccess(connection) is a static method of the CLOB class and as such cannot be mocked with Mockito.
(You can mock statics with Powermock).
I ended up testing just the 404 case then:
ResultSet mocked_resultset = Mockito.mock(ResultSet.class);
doReturn( null ) // cant' use "DEFAULT" since getClob() will throw npe anyway. Will test just 404 then.
.when(mocked_resultset).getString(1);
doReturn( false )
.when(mocked_resultset).next(); // or just return null in getCursor(2)
OracleCallableStatement statement = Mockito.mock(OracleCallableStatement.class);
doReturn( "testID" )
.when( statement ).getString(1);
doReturn( mocked_resultset )
.when( statement ).getCursor(2);
I'm testing the following method:
private String getHomeStateCountry(Details aDetails, String aCountry) {
String homeState = Constants.BLANK_SPACE;
if (Constants.USA.equalsIgnoreCase((aCountry))) {
if (aDetails.getStateCountry() != null) {
homeState = aDetails.getStateCountry().getStateName();
}
} else {
if (aDetails.getStateCountry() != null) {
homeState = aDetails.getStateCountry().getCountryName();
}
}
return homeState;
}
When writing JUnits for this method, Is it pointless to set the stateName and countryName for each test(so if something goes wrong, e.g. the state is returned instead of the country, then the fail message provides a more accurate explanation etc) or should each test only set the value under test, i.e. if I'm testing for other than USA, only set countryName and check the returned value?