test case issue - java

hi
I have one class,and in that class I have one method as follows:
I am using java.
public class ABC{
some code here...
..................
PreparedStatement pre;
public void insertUser(String firstName,String lastName){
pre.setString(1,firstName);
pre.setString(2,lastName);
pre.execute();
}
}
for above method I want to write the test case,I have created the test class as follows:
public class ABCTest{
ABC abc=new ABC();
public void testInsertUser(){
now here I want to write the assert statement,I want test whether insert is successful,
I want to test the method variable using assert(). Please tell me how to write test case for this in java.

You need to do something like these:
Check the count of rows before and after the INSERT and assert that the after count is one greater than the before count.
Do a SELECT and see if your row made it into the database.
Check the number of rows affected that is returned by the call and see that it equals one.

probably you have along with your 'insertUser' method other methods like 'selectUser' and 'removeUser' so in your testCase you should use 'selectUser' method to be sure that your user appear in DB, also in the end you should call 'removeUser' cause after the tests you should keep your data clean as it was before (for tests to be able to run multiple times on same test data with same results).

do you mean something like:
public void testInsertUser(){
ABC.insertUser(User.firstname, user.lastname);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT firstname_Colname, lastname_Colname FROM Your_Table");
boolean found = false;
while (rs.next())
{
found = ((User.firstname = rs.getString("firstname_Colname")) and (User.lastname = rs.getString("lastname_Colname")));
if (found)
{
break;
}
}
assertEquals('test failed!', true, found);
}
if yes you are actually testing the PreparedStatement which doesnt make any sense for me!

Related

How to dynamically append results to a mocked method in Mockito

I'm originally mocking java.sql.ResultSet like this:
ResultSet rs = mock(ResultSet.class);
when(rs.next()).thenReturn(true, false);
when(rs.getString(1)).thenReturn("foo");
when(rs.getString(2)).thenReturn("bar");
when(rs.getInt(3)).thenReturn(55);
The above code is for mocking a simple one level data mocking, and it's working without any issues.
However, we have more complicated cases in our code where we use ResultSet in multiple method calling levels. Here's a sample code for a nested calling for ResultSet.
void level1(){
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
String a = rs.getString(1);//Expected to return "foo"
String b = rs.getString(2);//Expected to return "bar"
int c = rs.getInt(3);//Expected to return 55
}
level2();
}
void level2(){
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
String a = rs.getString(1);//Expected to return "lorem"
String b = rs.getString(2);//Expected to return "ipsum"
}
level3();
}
void level3(){
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
String a = rs.getString(1);//Expected to return "alice"
int b = rs.getInt(2);//Expected to return 66
int c = rs.getInt(3);//Expected to return 77
}
level3();
}
To mock the method level1 in the above snippet, we have to write something similar to this
ResultSet rs = mock(ResultSet.class);
when(rs.next()).thenReturn(true, false, true, false, true, false);
when(rs.getString(1)).thenReturn("foo", "lorem", "alice");
when(rs.getString(2)).thenReturn("bar", "ipsum");
when(rs.getInt(3)).thenReturn(55, 77);
when(rs.getInt(2)).thenReturn(66);
As you can see from the above example, mocking the nested methods is not readable at all.
We are looking for a way to replace the unreadable mocking code with something more redable that will look like this:
ResultSet rs = mock(ResultSet.class);
when(rs.next()).thenReturnAndAppend(true, false);
when(rs.getString(1)).thenReturnAndAppend("foo");
when(rs.getString(2)).thenReturnAndAppend("bar");
when(rs.getInt(3)).thenReturnAndAppend(55);
when(rs.next()).thenReturnAndAppend(true, false);
when(rs.getString(1)).thenReturnAndAppend("lorem");
when(rs.getString(2)).thenReturnAndAppend("ipsum");
when(rs.next()).thenReturnAndAppend(true, false);
when(rs.getString(1)).thenReturnAndAppend("alice");
when(rs.getInt(2)).thenReturnAndAppend(66);
when(rs.getInt(3)).thenReturnAndAppend(77);
Is there a way in Mockito to achieve that?
I've already tried to use when().then() multiple times for the same method, but that overrides the previous mock for that method, and doesn't append values.
I've also tried to use OngoingStubbing to accomplish that but it throws an exception saying this is a bad behavior to use then on different lines.
I've also tried to create a custom mock method to store values in a map and load them from the map later
private Map<Object, Stream> mockingMap;
protected <T> void whenThen(T method, T value) {
if(!mockingMap.containsKey(method)) {
mockingMap.put(mock, (Stream<T>)Stream.of());
}
mockingMap.put(method, Stream.concat(mockingMap.get(method), Stream.of(value)))
when(method).thenAnswer(e -> {
mockingMap.get(method).next()
});
}
And will use this method like this:
whenThen(rs.getString(1), "foo");
whenThen(rs.getString(1), "lorem");
The issue with this implementation is that the value of method in whenThen method doesn't represent the mocked method rs.getString(1), which means that calling rs.getString(1) two times will result in two different values for the method parameter.
My first question is: Is there any built in method in Mockito that has a similar behavior to thenReturnAndAppend.
My second question is: If there's no similar method to thenReturnAndAppend, then how can I pass a unique key to the whenThen method that represents the method that we are trying to mock?
According to the documentation, you can do so using iterator-style stubbing:
https://javadoc.io/doc/org.mockito/mockito-core/2.24.5/org/mockito/Mockito.html#stubbing_consecutive_calls
Stubbing consecutive calls (iterator-style stubbing) Sometimes we need to stub with different return value/exception for the same method
call. Typical use case could be mocking iterators. Original version of
Mockito did not have this feature to promote simple mocking. For
example, instead of iterators one could use Iterable or simply
collections. Those offer natural ways of stubbing (e.g. using real
collections). In rare scenarios stubbing consecutive calls could be
useful, though:
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
//First call: throws runtime exception:
mock.someMethod("some arg");
//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));
//Any consecutive call: prints "foo" as well (last stubbing wins).
System.out.println(mock.someMethod("some arg"));
Your example would then look similar to:
PreparedStatement stmt = null;
ResultSet mockResult1 = Mockito.mock(ResultSet.class);
Mockito.when(mockResult1 .next()).thenReturn(true);
Mockito.when(mockResult1 .getString(1)).thenReturn("foo");
Mockito.when(mockResult1 .getString(2)).thenReturn("bar");
Mockito.when(mockResult1 .getInt(3)).thenReturn(55);
ResultSet mockResult2 = Mockito.mock(ResultSet.class);
Mockito.when(mockResult2 .next()).thenReturn(true);
Mockito.when(mockResult2 .getString(1)).thenReturn("lorem");
Mockito.when(mockResult2 .getString(2)).thenReturn("ipsum");
Mockito.when(mockResult2 .getInt(3)).thenReturn(55);
Mockito.when(stmt.executeQuery()).thenReturn(mockResult1).thenReturn(mockResult2);

junit test case for my api

i am new to writing junits.I have my below java api which gets a unique value every time from database.It contains just a single query.I need to write junit for below api.can anybody give some suggestions how should i approach??
public static int getUniqueDBCSequence() throws Exception
{
int w_seq = 0;
QueryData w_ps = null;
ResultSet w_rs = null;
try
{
w_ps = new QueryData("SELECT GETUNIQUENUMBER.NEXTVAL FROM DUAL");
w_rs = SQLService.executeQuery(w_ps);
while ( w_rs.next() )
{
w_seq = w_rs.getInt(1);
}
}
catch (Exception a_ex)
{
LOGGER.fatal("Error occured : " + a_ex.getMessage());
}
finally
{
SQLService.closeResultSet(w_rs);
}
return w_seq;
}
You are using only static methods : in the class under test but also in the dependencies of it.
It is really not a testable code with JUnit.
Besides, what you do you want to test unitary ?
Your test has no substantive logic.
You could make SQLService.executeQuery() a method instance to be able to mock it. But really which interest to mock it ?
To assert that the result is returned w_seq = w_rs.getInt(1); ?
It looks like technical assertions that have few value and maintaining unit tests with few value should be avoided.
Now, you could test with DBunit or tools to populate a in memory database and executes the code against.
But the query executed have a strong coupling with Oracle sequences.
So, you could have some difficulties to do it.

how to merge two different resultsets from two different DBs in java

I have two resultsets, one from DB2 and one from Sybase.
I want to merge these resultsets based on some condition,for which i have made one function which will take two resultsets and merge them.
But i am getting SQL exception- Resultset Closed
I am using Connection object and Prepared statement to connect to the respective DB and execute the query.
public void ExecuteDB2Query(SQLQuery){
Connection DB2con = DB2Sess.connection();
PreparedStatement statement = DB2con.prepareStatement(SQLQuery);
MyResulset1= statement.executeQuery();
}
Another method:
public void ExecuteSybaseQuery(SQLQuery){
Connection Sybasecon = SybaseSess.connection();
PreparedStatement statement = Sybasecon.prepareStatement(SQLQuery);
MyResulset2= statement.executeQuery();
}
Final merge method
puble void merge{
while(MyResultset1.next()){
while(MyResultset2.next()){
<some code here>
}
Do we have any way by which i can loop through these two result sets? without any exception.
It looks like you are trying to loop through those two result sets with a nested loop. That can't be done, since after the inner loop finished its first iteration, MyResultset2 cannot be used anymore.
I suggest you iterate over the two result sets separately and store their data in some Collections. Then you can iterate over those Collections however you like.
Ok, i'll give you your code check it.
public void ExecuteDB2Query(SQLQuery){
Connection DB2con = DB2Sess.connection();
PreparedStatement statement = DB2con.prepareStatement(SQLQuery,ResultSet.TYPE_SCROLL_INSENSITIVE);
myResulset1 = statement.executeQuery();
}
public void ExecuteSybaseQuery(SQLQuery){
Connection Sybasecon = SybaseSess.connection();
PreparedStatement statement = Sybasecon.prepareStatement(SQLQuery,ResultSet.TYPE_SCROLL_INSENSITIVE);
myResulset2 = statement.executeQuery();
}
public void merge{
while(myResultset1.next()){
myResultset2.first();
while(myResultset2.next()){
<some code here>
}
}
}
make changes in this code according to your requirement.

Query returning only empty value in java

I am using java to connect with oracle.This is the code which I have used
public List<FavouriteShop> getmyfavouriteshop(String username) {
List<FavouriteShop> res=null;
res = this.getJdbcTemplate().query("select * from(Select tbl_orderdetails.branch_name as myfavourite,tbl_orderdetails.branch_id as branch_id from tbl_orderdetails inner join tbl_ordermaster on tbl_orderdetails.order_master_id=tbl_ordermaster.ordermasterid where tbl_ordermaster.user_id='"+username+"' group by tbl_orderdetails.branch_name,tbl_orderdetails.branch_id order by count(tbl_orderdetails.branch_name) desc) where rownum<=3", new MyFavourite());
return res;
}
private class MyFavourite implements RowMapper<FavouriteShop> {
public FavouriteShop mapRow(ResultSet rs,int i) throws SQLException {
FavouriteShop g=new FavouriteShop();
g.setBranch_id(rs.getString("branch_id"));
g.setMyfavourite(rs.getString("myfavourite"));
return g;
}
}
I tried to execute same query in oracle I am getting output but not here and I am getting only empty result.
First, you have a possible SQL injection. You can avoid this by giving username as an argument to query
this.getJdbcTemplate().query("select * from (... where tbl_ordermaster.user_id=? ...) where rownum<=3",
new Object[]{ username }, new MyFavourite());
A possible reason for the empty result might be
... where tbl_ordermaster.user_id='"+username+"' ...
Usually, user_id is an integer value, but you compare it to a String and enclose it in quotes. Passing username as an argument to query as shown above, should already take care of this.
Usually it is not the same query or not the same database :)
Extract your query text to separate variable, print it to logs. Then copy-paste from logs to sql developer.
And check database and user name.
Also, it is possible that you inserted that entries but forgot to add COMMIT.

Database doesn't like reading values from a loop

I have a java database successfully connected to my java code. Thats all fine as it works and all.
When I store a result from the database into a variable ... it works perfectly.
Now as I have to do this 8 times I used a loop and a array however by using a try catch tool it gives out a error of, Error is: java.lang.NullPointerException
Futher investigation shows that it seems to not like the loop strangely.
public String Title []; //in class but out of any methods
public void gettinginfo ()
{
try
{
int AB = 0; //array base starts from 0
//ID in database starts from 1
for (int i = 1; i<=8; i++)
{
String query = "SELECT * FROM students WHERE ID = " + i;
Rs = St.executeQuery(query);
while (Rs.next())
{
Title[AB] = Rs.getString("StudentName");
AB++;
}
}
}
catch (Exception ex)
{
System.out.println("Error is: " + ex);
}
}
What line is your NullPointerException occurring on? Likely your Title array has not been initialized. If you know how many rows the query will return, you can say:
Title = new String[numRows];
But if you don't, you'll need to either run a SELECT count(*) ... query or use an ArrayList or other resizable list, instead of an array.
Your code is also very poorly structured, which is no small part of why you're having trouble debugging this. I've cleaned up your code below, with comments explaining my changes:
public class YourClass
{
private static final int MAX_ID = 8; // or however you want to set the size
private String[] title; // [] after the type is easier to read, lower case variables
private Connection conn; // I'm assuming the class will be provided a DB connection
// Note the Statement and ResultSet objects are not defined in the class, to
// minimize their scope.
public void queryInfo() // name suggests a query (potentially expensive) will be run
{
title = new String[MAX_ID]; // **initialize title**
// We use a try-with-resources block to ensure the statement is safely closed
// even better would be to use a PreparedStatement here
try(Statement st = conn.statement())
{
// You're executing 8 separate queries here, where one will do
String query = "SELECT * FROM students WHERE ID >= 1 AND ID <= "+MAX_ID;
// Again, we need to close the result set when we're done
try(ResultSet rs = st.executeQuery(query))
{
int i = 0;
while (rs.next())
{
title[i++] = rs.getString("StudentName");
}
} // close our ResultSet
} // close our Statement
}
// provide a separate getter method, rather than making the array public
public String[] getTitles()
{
return title;
}
}
There's still more that could be improved - using an array seems like a poor design, as does calling a method which populates a class variable rather than simply having queryInfo() return a new array. You can also look into using PreparedStatement. Hopefully these suggestions help.
Make sure that Title array and Statement St objects are and not null. These are the only two reasons that I suspect. Give FULL stacktrace if it doesn't work.
Title array is NULL. "new" this array to the size equal to number of rows. If you don't know the rows, fire a count(*) query first, find out the no of rows and then intantiate Title array or use ArrayList<String> instead of String array.
I am assuming that you have not initialized your Title array, you have to set it equal to something or it will just be null which will cause a nullPointerException, but as others have stated there is no way to be sure since your haven't given us a full stack trace or even the line number of the exception. In this case the exception should be handled as such:
try{
//your code here
}catch(Exception ex){
ex.printStackTrace();
}
This code will give you the full stack trace making it much easier to track down the issue.
Also you may want to consider using an ArrayList instead of an array:
List<String> Title = new ArrayList<String>();
Then to add to it:
Title.add(Rs.getString("StudentName"));
If you need it as an array later then:
String[] title = Title.toArray(new String[Title.size()]);
You can read more about ArrayLists here.

Categories

Resources