I'm creating a unit test for the below Java code which gets data from a database and, via a lambda, maps the data retrieved into a list:
List<Pair<String, String>> list = jdbcTemplate.query(MY_QUERY, (rs, rowNum) -> {
String code = rs.getString(1);
String name = rs.getString(2);
return new Pair<String, String>(code, name);
});
It's part of a Spring framework service class; the unit test is run via SpringJUnit4ClassRunner.
I've used Mockito to mock the jdbcTemplate object (of type NamedParameterJdbcTemplate).
I'm trying to mock the result of the jdbcTemplate. Looking at the method call, it looks like I need to mock this method in the NamedParameterJdbcTemplate class:
query(String sql, RowMapper<T> rowMapper)
I have tried this:
List<Pair<String, String>> pairList = ...;
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(RowMapper.class))).thenReturn(pairList);
... but when I run the unit test, the "list" variable is always null after the line of code has been passed, as if the mock hasn't been triggered to return my value.
The Mockito object is definitely being injected into the class.
Printing the mock's invocactions displays this:
[Mockito] Interactions of: Mock for NamedParameterJdbcTemplate, hashCode: <n>
1. namedParameterJdbcTemplate.query("query", my.package.MyClass$$Lambda$114/1274225913#3e134896);
Is there anything I'm obviously doing wrong? Thanks in advance for any assistance.
try Mockito.any(Function.class)
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(Function.class))).thenReturn(pairList);
I moved the mock's configuration to where it's created:
#Bean(name = "jdbcTemplate")
public NamedParameterJdbcTemplate jdbcTemplate() {
NamedParameterJdbcTemplate jdbcTemplate = Mockito.mock(NamedParameterJdbcTemplate.class);
Pair<String, String> pair = new Pair<String, String>(CODE, NAME);
List<Pair<String, String>> pairList = new ArrayList<Pair<String, String>>();
pairList.add(pair);
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(RowMapper.class))).thenReturn(pairList);
return jdbcTemplate;
}
It works now.
Related
I want to unit test the MongoItemReader part of springbatch so
for testing
#Autowired
MongoItemReader mongoItemReader;
#Test
public void readerTest() throws Exception {
assertNotNull(mongoItemReader.read());
}
Is it enough for testing reader? and is there a way to get the read data in test cases from reader? cause doPageRead() in MongoItemReader.java is protected, that is why I can not test the read data
Also in the reader bean :
#Bean
public MongoItemReader<User> userReader() {
userRepository.save(USER_SAMPLE);
Map<String, Sort.Direction> sort = new HashMap<>();
sort.put("_id", Sort.Direction.ASC);
return new MongoItemReaderBuilder<User>().template(this.mongoTemplate)
.targetType(User.class)
.saveState(false).pageSize(10)
.jsonQuery(String.format("{Dep: '%s'}", department))
.sorts(sort).template(mongoTemplate)
.name("users")
.build();
}
when I replace .jsonQuery(String.format("{Dep: '%s'}", department)) with `
.query(query)
`
and query is :
Query query = new Query().with(PageRequest.of(0, 10)).with(Sort.by(Sort.Direction.ASC, "_id"));
query.addCriteria(Criteria.where("Dep").is(departmentValue));
it does not pass the test until I remove the last line of criteria
why adding criteria conditions to query object in reader bean makes assertNotNull(mongoItemReader.read()); failling
I have the following code in my Java class in a Spring Boot (v. 2.2.1.RELEASE) application:
#Inject
private JdbcTemplate jdbcTemplate;
#Inject
private MyRowCallbackHandler myRowCallbackHandler;
public void myMethod() {
jdbcTemplate.query(MY_QUERY, myRowCallbackHandler);
}
The JDBC template object is an implementation of org.springframework.jdbc.core.JdbcTemplate and the handler is an implementation of org.springframework.jdbc.core.RowCallbackHandler.
With JUnit version 4 and Mockito, can I mimic the retrieval of one or more rows from a database by the query method, thus calling the handler's processRow() method?
Thanks for any assistance.
I ran into this problem in my own code, thought I'd share the solution here, even though it's slightly different than the situation above as I mock the jdbcTemplate as well.
#InjectMocks
private JdbcOperationRepository jdbcOperationRepository;
#Mock
private NamedParameterJdbcTemplate mockJdbcTemplate;
#Test
public void testMyResults() {
final ResultSet mockResult1 = mock(ResultSet.class);
when(mockResult1.getString(MY_COLUMN)).thenReturn(value);
// ... other when statements to mock the returned data
doAnswer(invocation -> {
RowCallbackHandler callbackHandler = invocation.getArgument(2);
callbackHandler.processRow(mockResult1);
callbackHandler.processRow(mockResult2);
return null;
}).when(mockJdbcTemplate).query(any(), any(), any(RowCallbackHandler.class));
}
I was struggling with the same problem. First, you have to keep in mind that you can mock almost anything in spring boot using Junit tests.
I am writing the solution in a generalized pattern so that everyone can get an idea how it gets implemented and used.
Suppose, we have a function implemented in our BookService.java class:
#Service
public class BookService {
#Inject
private NamedParameterJdbcOperations jdbcTemplate;
#Inject
private FileHelper fileHelper;
public List<BookDTO> getBooks(Long libraryId){
String sql = fileHelper.getFileContents("SQL_FILE_PATH");
Map<String, Object> parameterMap = new HashMap<>();
if(libraryId!=null){
parameterMap.put("libraryId", libraryId);
}
List<BookDTO> books = new ArrayList<>();
jdbcTemplate.query(sql, parameterMap, rs -> {
BookDTO book = new BookDTO();
book.setId(rs.getLong("id"));
book.setName(rs.getString("name"));
if(rs.getObject("librarian") != null){
book.setLibrarian(rs.getString("librarian"));
}
books.add(book);
});
return books;
}
}
Now, we want to mock the functionality of the jdbcTemplate.query() method for the above service class.
Our test should be written in this pattern:
public class BookServiceMockTest {
#Mock
private NamedParameterJdbcOperations jdbcTemplate;
#Mock
private FileHelper fileHelper;
private BookService mockBookService;
#Before
public void setup(){
mockBookService = new BookService();
// using reflectionUtils setFields of the fileHelper and jdbcTemplate.
// ....
}
#Test
public void getBooksTest(){
when(fileHelper.getFileContents("SQL_FILE_PATH")).thenReturn("SOME SQL");
doAnswer(invocation -> {
// we are going to mock ResultSet class.
ResultSet rs = Mockito.mock(ResultSet.class);
when(rs.getLong("id")).thenReturn(1L);
when(rs.getString("name")).thenReturn("Game of Thrones");
// this will mock the if() statement
when(rs.getObject("librarian")).thenReturn("John Doe");
// this will mock the actual get statement call on getString() inside the if statement
when(rs.getString("librarian")).thenReturn("John Doe");
// the argument index is important here.
// we are doing getArgument(2).
// This means the third parameter passed in the jdbcTemplate.query(Param0, Param1, Param2) in the BookService.getBooks() function.
RowCallbackHandler rch = (RowCallbackHandler) invocation.getArgument(2);
// as we are mocking only one row..
rch.processRow(rs);
/* // if we wanter two or more results:
when(rs.getLong("id")).thenReturn(1L).thenReturn(2L);
when(rs.getString("name")).thenReturn("Game of Thrones").thenReturn("Dance of the Dragon");
int n = 2; // no of rows..
for(int i=0; i<n; i++){
rch.processRow(rs);
}
*/
return null;
})
// the parameters used here are important. Any mismatch will result in unsuccessful.
.when(jdbcTemplate).query(eq("SOME SQL"), anyMap(), any(RowCallbackHandler.class));
List<BookDTO> books = mockBookService.getBooks(anyLong());
verify(jdbcTemplate, times(1)).query(eq("SOME SQL"), anyMap(), any(RowCallbackHandler.class));
assertThat(books).hasSize(1);
}
}
I hope this answered what you were looking for!
I am new to junit testing using mockito in java. I have been stuck at one point.
I have one abstract class AbstractA which needs to test.
Implementation of AbstractA as below.
public abstract class AbstractA implements ADao {
#Autowired
NamedParameterJdbcTemplate jdbcTemplate;
#Override
public List<String> getColumns(Set<String> ids) {
String sql = query();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("ids", ids);
return jdbcTemplate.query(sql, paramMap, rowMapper());
}
abstract protected String query();
abstract protected AbstractIpRowMapper rowMapper();
}
And a test class for above is AbsractATest
public class AbsractATest {
#InjectMocks
AbsractA abstractA;
#Mock
NamedParameterJdbcTemplate jdbcTemplate;
#Mock AbstractIpRowMapper abstractIpRowMapper;
#Before
public void setUp() throws IOException, SQLException {
abstractA=Mockito.mock(AbsractA.class, Mockito.CALLS_REAL_METHODS);
jdbcTemplate=mock(NamedParameterJdbcTemplate.class);
List<String> idsinput=new ArrayList<String>();
idsinput.add("123");
idsinput.add("124");
idsinput.add("125");
Set<String> ids=new LinkedHashSet<String>();
ids.add("123");
ids.add("124");
ids.add("125");
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("ids", ids);
String query="select ids from tableA where ids=:ids";
when(abstractA.query()).thenReturn(query);
when(jdbcTemplate.query(query, paramMap,rowMapper())).thenReturn(idsinput);
org.springframework.test.util.ReflectionTestUtils.setField(abstractA, "jdbcTemplate", jdbcTemplate);
}
protected AbstractIpRowMapper rowMapper() {
return absractIpRowmapper;
}
But after running this test case I am getting empty value for
abstractA.getColumns();
Please help me to understand what I should need to do in above case.
Run doCallRealMethod().when(abstractA).getColumns(); in the unit test
You don't need to test abstract class tdd knows nothing about abstract classes, make it normal class and only you have same code duplication with two or more class lift it up to abstract, test for this class will not change. Specify sql query string and IPRowMapper as constructor parameters this simplify and make your code more clean. Second, you don't need such complicated setup for tests, you need only to verify interactions, not return value, verify only NamedParameterJdbcTemplate mock, whats values passed to it.
I am trying to make a unit test on a method from a DAO class. Dao class is using JDBC. I am trying to unit test it but without using test data base. I must test it using some data structure for storing all the information.
public class UserProfilesDao extends JdbcDaoSupport {
#Autowired
private MessageSourceAccessor msa;
public long getUserServiceId(long userId, int serviceId) {
String sql = msa.getMessage("sql.select.service_user_id");
Object[] params = new Object[] { userId, serviceId };
int[] types = new int[] { Types.INTEGER, Types.INTEGER };
return getJdbcTemplate().queryForLong(sql, params, types);
}
}
getJdbcTemplate() appears to be a method that you want to mock out.
In your unit test, declare a UserProfilesDao member as follows:
#Spy
private UserProfilesDao classToTest;
the #Spy is a mockito annotation.
in your unit test declare a setup method as follows:
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
doReturn(what ever you want).when(classToTest).queryForLong(
any(xxx.class),
any(yyy.class),
any(zzz.class));
}
where xxx, yyy, and zzz are the queryForLong parameter types.
You can store data in DTO Objects and maintain DTOs in a Map with proper keys.
For test, retrieve data from map using key according to your need!
We are using spring oauth and there are several places where we need to use inheritance.
In the immediate case we are extending TokenEndpoint
public class MyTokenEndpoint extends TokenEndpoint {
//...
public ResponseEntity<OAuth2AccessToken> getAccessToken(
Principal principal,
MyParams myParams,
#RequestParam Map<String, String> allParams) {
// .. Stuff Happens
updateParamsWithStuff(allParams);
return super.getAccessToken(
principal, myParams.grantType(), allParams);
}
//...
}
Now what I want to test is if the map passed to super.getAcccessToken has been filled with Stuff. My simple way was to spy on the map passed in, but this relies on implemetation details and does not actually insure that stuff is in the map passed super.getAccessToken
We are using Mockito, I have seen comments that this will not work, and one that implies it may. Can this be done in any of the mocking frameworks?
See both answers on ( Can I mock a superclass's constructor with Mockito/Powermock?, the checked one says impossible, but given the discussion on the second answer I just had to try.)
After reading that I tried the following:
MyTokenEndpoint spyEndpoint = Mockito.spy(endpoint); //endpoint Set-up previously
Mockito.doAnswer(new Answer<ResponseEntity<OAuth2AccessToken>>() {
#Override
public ResponseEntity<OAuth2AccessToken>
answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Map<String, String> params = (Map<String, String>) args[2];
System.out.printf("%s\n", params.toString());
return new ResponseEntity<OAuth2AccessToken>(HttpStatus.ACCEPTED);
}
}).when(((TokenEndpoint) spyEndpoint))
.getAccessToken(any(Principal.class),
anyString(), (Map<String, String>) anyMap());
theResponse = spyEndpoint
.getAccessToken(principal,
myPrams,
currentMap);
But the code in answer never gets called.
Am I barking up the wrong tree?? Is this possible in any mocking framework?
Why do you need to mock? You are already extending the class--just override that method, examine the data passed in then forward the data to the parent.
Such a test can be easily written with JMockit:
#Test
public void mockCallToSuper(#Mocked final TokenEndpoint mockedBase)
{
final Principal principal = null; // or whatever
MyParams myParams = new MyParams();
Map<String, String> params = new HashMap<String, String>();
ResponseEntity<OAuth2AccessToken> accessToken =
new MyTokenEndpoint().getAccessToken(principal, myParams, params);
// asserts on "accessToken"
new Verifications() {{
Map<String, String> actualParams;
mockedBase.getAccessToken(
principal, (MyParams) any, actualParams = withCapture());
assertEquals("abc", actualParams.get("A"));
assertEquals("another item", actualParams.get("B2"));
}};
}