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.
Related
I have the following service method:
public CommandDTO update(UUID uuid, EmployeeRequest request) {
final List<Product> productList = productRepository
.findAllByUuidOrderByOrderNumber(uuid);
final List<UUID> uuidList = request.getUuidList();
for (int i = 0; i < uuidList.size(); i++) {
Product product = productList.get(i);
product.setOrderNumber(i + 1);
// how can I get the product value in this line?
}
return CommandDTO.builder().uuid(uuid).build();
}
Normally, I use ArgumentCaptor in order to get values passing to repository or service. Howevcer, in this example, the product value that I want to get after product.setOrderNumber(i + 1); is not passing service or repository. For this reason I cannot get it. I am not sure if it would be possible using #Spy or doAnswer, but as far as I know, these methods cannot be used as the value is not passing to service or repo. Any idea?
You can mock you repository to return list of mock's:
public test() {
Product product1 = mock(Product.class);
Product product2 = mock(Product.class);
List list = Arraylist();
list.add(product1);
list.add(product2);
when(productRepositoryMock.findAllByUuidOrderByOrderNumber(uuid))
.thenReturn(list)
when(product1).setOrderNumber(captor.capture)
In this case you can use ArgumentCaptor here, but I belive it's redundant in this case, and simple verify call will be enough
service.update(.....);
verify.(product1).setOrderNumber(value);
The product variable comes from productList, which in turn comes from the repository.findAllByUuidOrderByOrderNumber() method. So if you mocked your repository, you could write something like this:
Product givenProduct = new Product();
UUID givenUUID = UUID.randomUUID();
// Create an EmployeeRequest with a `uuidList`
EmployeeRequest givenRequest = new EmployeeRequest(/* TODO */);
// Use Mockito to return a `productList` you choose
// This uses a static import of `Mockito.when()`
when(productRepository.findAllByUuidOrderByOrderNumber(givenUUID)).thenReturn(List.of(givenProduct));
service.updateRequest(givenUUID, givenRequest);
Theoretically you could even return a mocked product in the test logic above, but I suggest using a real Product object.
And now whatever happens to that product, can be asserted within your test.
For example:
// `givenProduct` is element 0, and thus will get an orderNumber of 1
assertThat(givenProduct.getOrderNumber()).isEqualTo(1);
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.
I'm making a test for a service with a mock.
The problem is to create and inject instance directly from the class to test.
The source is shown below.
public OrderOutDTO createOrder(OrderSessionDTO orderSessionDTO) {
Order order = orderRepository.save(new Order(orderSessionDTO));
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
CreateOrderReqDTO createOrderReqDTO = mock(CreateOrderReqDTO.class);
createTrace(order, callServiceOrder.getData().getReceipt().getTransactionHash(), Trace.PUBLIC);
return new OrderOutDTO(order, null);
}
and test source is shown below.
#Test
public void createOrder() {
// given
CallService callService = mock(CallService.class);
CreateOrderResDataDTO createOrderResDataDTO = mock(CreateOrderResDataDTO.class);
// when
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
// then
assertThat(order, is(Matchers.notNullValue()));
assertThat(order.getOrder(), is(Matchers.notNullValue()));
assertThat(order.getOrder().getReceiver().getName(), is("test"));
}
I thought this test would finish well. But in the code below, it returned null and failed.
// callService.createOrder(new CreateOrderReqDTO(order)) return null
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
It doesn't seem to recognize it because the service injects a new instance. I want the mock data returned. What should I do?
In the following line you're mocking behavior on createOrderReqDTO as param:
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
whereas further, you're passing some other object:
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
This behavior is not recognized, you would have to pass the same thing you mocked before.
I found it myself!
I use argumentMatchers.
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
to
when(callService.createOrder(any())).thenReturn(createOrderResDTO);
thank you.
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.
I've got a class like the following:
class A
{
public method doSomething()
{
//....
DAO dataAccessor = new DAO();
List<Object> result1 = dataAccessor.getData(dataAccessor.getSql1());
List<Object> result2 = dataAccessor.getData(dataAccessor.getSql2());
//.. do some stuff with the results
}
Now, I use jMockit for testing the above function, by mocking the DAO class.
This is how my test class looks like:
class A_Test
{
private A myAClass;
#Mocked DAO mockedDAO;
List<Object> resultToSql1, resultToSql2;
// ... Some initializations...
#Test
public void testDoSomething()
{
new NonStrictExpectations()
{
mockedDAO.getSql1(); result = "SQL1";
mockedDAO.getData(withEqual("SQL1")); result = resultToSql1;
mockedDAO.getSql2(); result = "SQL2";
mockedDAO.getData(withEqual("SQL2")); result = resultToSql2;
};
myAClass.doSomething();
}
}
Now, it seems that the second expectation regarding getData() masks the first one, i.e. the mock object behaves as if I never declared the first lines in the expectation (the ones that handle sql1):
The first call to getData() returns empty collection, instead of the values with which I initialized resultToSql1. The second call returns resultToSql2, as expected.
If I comment the following line:
mockedDAO.getData(withEqual("SQL2")); result = resultToSql2;
the first call is returning what I defined - resultToSql1, and the second returns empty collection.
This makes sense.
So, what am I doing wrong? ?How can I define two different return values from getData() based on the parameters of the call?
Any help would be appreciated.
Thanks!
So, After digging more deeply inside the manual, I found that:
...But what if a test needs to decide the result of a recorded invocation based on the arguments it will receive at replay time? We can do it through a mockit.Delegate instance ...
So, in order to solve the above problem, the expectations block should look like this:
new NonStrictExpectations()
{
mockedDAO.getSql1(); result = "SQL1";
mockedDAO.getSql2(); result = "SQL2";
mockedDAO.getData(anyString);
result = new mockit.Delegate()
{
List<Object> getData(String sql)
{
if (sql.equals("SQL1"))
return resultToSql1;
if (sql.equals("SQL2"))
return resultToSql2;
return null;
}
}
};