I'm writing a test case for Email DAO layer. which is something like:
@Repository
@PropertySource({ "classpath:/query.properties" })
public class DaoLayerImpl implements DaoLayerDao {
/** The jdbc template. */
@Qualifier("mariaJdbcTemplate")
@Autowired
private JdbcTemplate jdbcTemplate;
/** The find staged query. */
@Value("${someQuery}")
String someQuery;
@Override
public List<SomeBean> getData() throws MariaDbException {
List<SomeBean> listOfData = new ArrayList<>();
try {
listOfData = jdbcTemplate.query(someQuery,
new BeanPropertyRowMapper<SomeBean>(SomeBean.class));
} catch (RuntimeException e) {
logger.error("RuntimeException in ", e);
}
return listOfData;
}
}
The Test case for this layer is :
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@PropertySource("classpath:application-test.properties")
public class EmailDaoLayerTest {
@MockBean
JdbcTemplate jdbcTemplate;
@InjectMocks
DaoLayerImpl dao;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
jdbcTemplate = Mockito.mock(JdbcTemplate.someQuery);
ReflectionTestUtils.setField(dao, "jdbcTemplate", jdbcTemplate);
}
@Test
public void testCaseForGetData() throws Exception {
List<SomeBean> beanObject = new ArrayList<>();
beanObject.add(new SomeBean());
beanObject.add(new SomeBean());
beanObject.add(new SomeBean());
System.out.println(beanObject.size()); // 3
when(jdbcTemplate.query("someQuery",
new BeanPropertyRowMapper<SomeBean>(SomeBean.class))).thenReturn(beanObject);
List<SomeBean> obj = dao.getData();
System.out.println(obj.size()); //0
System.out.println("Done");
}
}
After mocking the object size comes out to be 0 instead of 3. The size of the object before returning is 3. when i actually hitted the DAO, the size of the object comes out to be 0, whereas i had already mocked the jdbc template using when-then .
What is the correct way to mock Bean Property Row Mapper class?
Let me answer the question and then criticize your approach, maybe it will help to better understand how the solution should look like at the end.
So to answer your question:
Technically you can probably do something like:
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.any;
...
Mockito.when(jdbcTemplate.query(eq("someQuery"),
any(BeanPropertyRowMapper.class)).thenReturn(....);
However, you should ask yourself what exactly are you trying to test here? You have a relatively expensive integration test here that runs the Spring Context (it works with SpringRunner) and creates many objects under the hood.
However based on the method to be tested - I don't see that there is any "meaningful" (subject to tests) code to be tested. You could test that given the query, the BeanPropertyRowMapper indeed can convert the response to instances of SomeBean
but then again you mock it and it doesn't really run.
You could check that the query you've prepared runs against the Database and returns the expected results, but it doesn't seem that you prepare any database here.
So If the purpose is coverage - then yes you will be covered, but the tests are not about the coverage, but about making you "sure" that your code works properly. In this case, running the Spring Driven integration Test (with application context and everything) seems to be a huge overkill, MockitoRunner
could do the job