How to write Junit for jdbcTemplate call method - java

I am stuck in junit, I have to write junit for one of my dao mathod, here is my test code
#Test
public void testUpdateFeedback() throws SQLException {
List<SqlParameter> parameters = Arrays.asList(new SqlParameter(Types.NVARCHAR));
Mockito.when(jdbcTemplate.call(Mockito.any(CallableStatementCreator.class),
eq(parameters))).thenReturn(Mockito.anyMap());
Integer count = daoImpl.updateFeedBack(...somedata...);
assertEquals(1, count);
}
but it is throwing error
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
here is my dao code
public Integer updateFeedBack(Requestfeedback somedata) {
List<SqlParameter> parameters = Arrays.asList(new SqlParameter(Types.NVARCHAR));
jdbcTemplate.call(new CallableStatementCreator() {
#Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
CallableStatement cs = con.prepareCall("call updatefeedbackprocedure(?)");
int count = 0;
cs.setString(++count, "abc");
return cs;
}
}, parameters);
return 1;
}
Even If I use below code it does not work
Mockito.when(jdbcTemplate.call(Mockito.any(CallableStatementCreator.class), Mockito.anyList())).thenReturn(Mockito.anyMap());
please help thanks.

Seriously I do not recommend to test with Mock for this case since you are testing the DAO which is the data access layer , and the best way to test the data access layer is test with the actual DB but not the mock. Because in the end you still need to have some kind of integration test to verify your application can really get and update data from/to DB correctly and this DAO is the most appropriate place to do it.
You can check with Testcontainers which allows you to test with a containerised version of the DB which in theory should be very close to your actual production DB. You can refer to this for an example.

Related

Simple Oracle query using JDBI from DropWizard doesn't execute/return result

I have a DropWizard project with 2 database connections: one MySql and one Oracle (v11). The MySql connection and queries work just fine. I'm not getting any data from my Oracle queries and there are no errors in my logs.
My DOA looks like this:
public interface DummyDao {
#SqlQuery(
"select prod_sku, initial_qty, current_qty" +
" from prod_detail" +
" where prod_sku = :skuNumber")
#Mapper(DummyMapper.class)
Dummy getSku(#Bind("skuNumber") String skuNumber);
}
My mapper looks like this. When I added log statements to the mapper, I was able to verify it is never called.
public class DummyMapper implements ResultSetMapper<Dummy> {
public Dummy map(int index, ResultSet r, StatementContext ctx)
throws SQLException {
return new Dummy(
r.getString("prod_sku"),
r.getLong("initial_qty"),
r.getLong("current_qty"));
}
}
The DAO is being initialized in my application's run method via the following code:
public class ProductServiceApplication extends Application<ProductServiceConfiguration> {
DataSource sb_ds;
DBI sb_dbi;
DummyDao dummyDao;
#Override
public void run(
final ProductServiceConfiguration configuration,
final Environment environment) {
sb_ds = configuration.getSbliveDataSourceFactory()
.build(environment.metrics(), "sblive");
sb_dbi = new DBI(sb_ds);
dummyDao = sb_dbi.onDemand(DummyDao.class);
}
}
In order to verify there's nothing wrong with my connection, I temporarily added the following code to my run method and it returns the expected result:
try (Handle h = sb_dbi.open()) {
List<Map<String,Object>> result =
h.select("select initial_qty, current_qty from prod_detail where prod_sku = '10501034520008'");
System.out.println("bootstrap: " + result.toString());
}
Executing my DAO's getSku method with the same parameter returns null.
Can someone tell me what I'm doing wrong or point me to measures I can take to figure out what's causing this? I tried to debug it, but I simply don't know enough about JDBI internals to make any sense of what I'm looking at.
I found the issue. The problem is that the column associated with the bind variable is defined as CHAR(20) -- not VARCHAR(20) -- and the actual parameter value has a length of 14. When I execute the statement directly (using the handle or from SqlDeveloper), it works fine. But when using a prepared statement and bind variables, it's broken.
Padding the parameter out to 20 characters resolves the issue.

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.

Mockito/Realm (when-then): how to pass arguments from method to its submethod

Trying to unit test a project that uses Realm. I stubbed realm methods to just test my own code and found a problem with RealmQuery. I want to test whether an object is (1) added to the Realm db; (2) can be retrieved; (3) if that object's set attribute matches what I expect. Here are parts of my setup() and Test.
How I stub a realm database (someList is global & List<>) in setup()
SomeRealmObject some1;
some1.setId(1);
some1.setName("some1");
SomeRealmObject some2;
some2.setId(2);
some2.setName("some2");
someList = new ArrayList<SomeRealmObject>();
someList.add(some1);
someList.add(some2);
How I stub copying to Realm (add function) in setup()
when(mockRealm.copyToRealm).then(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
SomeRealmObject some = (SomeRealmObject) args[0];
userList.add(user);
return user;
}
});
How I stub RealmQuery (search function) in setup()
RealmQuery someRealmQuery = someRealmQuery(); //followed mockito example on github
when(mockRealm.where(SomeRealmObject.class)).thenReturn(someRealmQuery);
when(realmQuery.equalsTo(anyString, anyInt).thenReturn(someRealmQuery);
when(realmQuery.findFirst()).then(findFirstAnswer);
Problem starts here. I need realmQuery.equalsTo(...) to pass its arguments to the next method in the chain. I think it necessary (but I may be wrong) because I should test two methods that follow: findFirst() and findAll(). Any Ideas?
How I stub findFirst() in setup()
Answer findFirstAnswer = new Answer(){
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String key = args[0].toString(); //Let's just use an Id search for
int id = (int) args[1]; //an example.
for(int count = 0; someList.get(count) != null; count++){
if(someList.get(count).getId == id){
return someList.get(count);
}
return null; //test will fail, someRealmObject not found
}
}
How I unit test my createSomeObject (e.g. createAccount)
#Test
public void create_someObj_test() {
String expectedReturnedName = "someName";
String actualReturnedName;
SomeRepositoryImpl manager; //Class with business logic (mvp pattern)
SomeRepositoryImpl.initialize();
manager = someRepositoryImpl.getInstance();
SomeRealmObject some = new SomeRealmObject();
some.setID(6);
some.setName(expectedReturnedName);
//mock adding user to realm, should actually add it to a list
mockRealm.beginTransaction();
mockRealm.copyToRealm(some);
mockRealm.commitTransaction();
actualReturnedName = mockRealm.where(SomeRealmObject.class).equalTo("id", some.getId()).findFirst().getName().toString();
//PASS if object exists and name matches
//FAIL if name does not match
//FAIL if nullPointerException because no match/object not found
assertEquals(expectedReturnedName, actualReturnedName );
}
This is not a direct answer to your question. A direct answer would involve a discussion of what findFirstAnswer is and what its name property contains.
Instead, though, I would ask: "what are you trying to test"? This is not quite a test of the Realm DB library (a good thing). It looks to me almost like a test of Mockito! If the test succeeds, you will know that Mockito Mocks can return an object with a certain name.
It is common practice to wrap a data layer in a very thin API, something like the Data Access Objects popular with Spring and the like. If you can mock the data API, you can test the heck out of your business layer. If your data API needs testing, you can also test things like "does this API call get translated into the proper query?" or "does the API crash if the result is empty?".
Sorry for the oblique answer but I think if you revisit the question of what you are trying to test, this entire problem might evaporate.

Doesn't receive an error in java test

My test shouldn't pass. I should receive an error at row #2, because I put a wrong value new Long(0) at row #1.
Please tell me where is my mistake.
Thanks.
#Test
public void getPersonListByOtdelIdTest() {
Long otdelId = new Long(454);
ArgumentCaptor<Long> argumentOtdelId = ArgumentCaptor.forClass(Long.class);
SessionFactory mockedSessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
Query query = mock(Query.class);
PersonDAOImpl personDAO = new PersonDAOImpl(mockedSessionFactory);
when(mockedSessionFactory.getCurrentSession()). thenReturn(session);
when(session.createQuery("FROM Person P where P.otdel.otdelId = :otdelId")).thenReturn(query);
#1--> when(query.setParameter("otdelId", new Long(0))).thenReturn(query);
when(query.list()).thenReturn(persons);
List<Person> expectedPersons = personDAO.getPersonListByOtdelId(otdelId);
verify(mockedSessionFactory).getCurrentSession();
verify(session).createQuery("FROM Person P where P.otdel.otdelId = :otdelId");
verify(query).setParameter(eq("otdelId"), argumentOtdelId.capture());
verify(query).list();
#2--> assertEquals(otdelId, argumentOtdelId.getValue());
assertTrue(expectedPersons.containsAll(persons));
}
public class PersonDAOImpl implements PersonDAO {
public List<Person> getPersonListByOtdelId(Long otdelId) {
Query query = sessionFactory.getCurrentSession().createQuery("FROM Person P where P.otdel.otdelId = :otdelId");
query.setParameter("otdelId", otdelId);
List<Person> listPersons = query.list();
return listPersons;
}
}
I don't see why you would expect an assertion failure at #2. Your test passed in 454 (as a Long) into getPersonListByOtdelId(), so that will be passed to query.setParameter(). The when() code in #1 is essentially a no-op, because there is no call to query.setParameter() with those values, but Mockito won't complain if the call specified in a when() never happens, and the code under test doesn't check the return value, so there's no exception.
In any case, you don't need an ArgumentCaptor; you just need to have Mockito verify that the correct value was passed to setParameter()
In fact, many of verify calls aren't needed you could just do this:
#Test
public void getPersonListByOtdelIdTest() {
Long otdelId = 454L; // or = Long.valueOf(454); don't use new Long
SessionFactory mockedSessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
Query query = mock(Query.class);
when(mockedSessionFactory.getCurrentSession()).thenReturn(session);
when(session.createQuery("FROM Person P where P.otdel.otdelId = :otdelId"))
.thenReturn(query);
when(query.setParameter("otdelId", otdelId)).thenReturn(query);
when(query.list()).thenReturn(persons);
PersonDAOImpl personDAO = new PersonDAOImpl(mockedSessionFactory);
List<Person> result = personDAO.getPersonListByOtdelId(otdelId);
verify(query).setParameter("otdelId", otdelId);
assertEquals(result, persons);
}
You don't need to verify that getCurrentSession() is called, because if it wasn't the code under test wouldn't get a session. You don't need to verify that the correct query was passed to createQuery(), because of the code under test used a different query, Mockito wouldn't return a mock query (unless, of course, you use RETURNS_MOCKS).
That all being said, I don't think the above test is a good test. The test is almost exactly mirroring the code, and it doesn't verify that the code will work. In other words, it's a change detector test.
I wouldn't use a mocking framework to test PersonDaoImpl. Instead, I would write a test that started an in-memory database, using a schema file that is also used to create the actual table in production.
I would use a mock for tests for a class that depends on PersonDAO.

Test method that returns void

I have a void method and I want to test it. How do I do that?
Here's the method:
public void updateCustomerTagCount() {
List<String> fileList = ImportTagJob.fetchData();
try {
for (String tag : fileList) {
Long tagNo = Long.parseLong(tag);
Customer customer = DatabaseInterface.getCustomer(tagNo);
customer.incrementNoOfTimesRecycled();
DatabaseInterface.UpdateCustomer(customer);
}
} catch(IllegalArgumentException ex) {
ex.printStackTrace();
}
}
when the method returns void, you can't test the method output. Instead, you must test what are the expected consequences of that method. For example:
public class Echo {
String x;
public static void main(String[] args){
testVoidMethod();
}
private static void testVoidMethod() {
Echo e = new Echo();
//x == null
e.voidMethod("xyz");
System.out.println("xyz".equals(e.x)); //true expected
}
private void voidMethod(String s) {
x = s;
}
}
It might not be always true, but basic concept of unit test is to check if function works as expected and properly handling errors when unexpected parameters/situation is given.
So basically unit test is against the functions that takes input parameters and return some output so we can write those unit test.
The code like yours, however, includes some other dependency (database call) and that's something you can't execute unless you write integration-test code or real database connection related one and actually that's not recommended for unit test.
So what you need to do might be introducing unit test framework, especially Mockto/Powermock or some other stuff that provides object mocking feature. With those test framework, you can simulate database operation or other function call that is going to be happening outside of your test unit code.
Also, about how do I test void function, there is nothing you can with Assert feature to compare output since it returns nothing as you mentioned.
But still, there is a way for unit test.
Just call updateCustomerTagCount() to make sure function works. Even with just calling the function, those unit test can raise your unit test coverage.
Of course for your case, you need to mock
ImportTagJob.fetchData();
and
DatabaseInterface.getCustomer(tagNo);
and have to.
Let mocked
ImportTagJob.fetchData();
throw empty list as well as non-empty list and check if your code works as you expected. Add exception handling if necessary. In your code, there are two condition depends on whether fieList are null or non-null, you need to test it.
Also, mock those objects and let them throw IllegalArgumentException where you expect it to be thrown, and write an unit test if the function throws a exception. In Junit, it should be like
#Test(expected = IllegalArgumentException.class)
public void updateCustomerTagCountTest(){
// mock the objects
xxxxx.updateCustomerTagCount();
}
That way, you can ensure that function will throw exception properly when it has to.

Categories

Resources