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!
Related
Here is the class and the method I am trying to unit test.
public abstract class ShowService {
#Resource(name = "blogCoreSolrClient")
private SolrClient blogCoreSolrClient;
protected Show findShow(ClientRegion clientRegion, TargetLocale locale, Integer showId) {
SolrQuery query = new SolrQuery();
query.setQuery("type:" + SolrType.show)
.addFilterQuery(getRegionQuery(clientRegion))
.addFilterQuery(getLanguageFallbackQuery(locale))
.addFilterQuery("show_id:" + showId)
.setRows(1);
QueryResponse response = blogCoreSolrClient.query(query);
List<Show> shows = response.getBeans(Show.class);
if (shows != null && shows.size() > 0) {
return shows.get(0);
}
return null;
}
public static class SyndicatedShow {
#Field("show_id")
public Integer showId;
#Field("path_value")
public String pathValue;
}
}
Here's my Unit test written using Mockito
public class ShowServiceTest {
public final QueryResponse queryResponse = Mockito.mock(QueryResponse.class);
public final SolrClient blogCoreSolrClient = Mockito.mock(SolrClient.class);
public final SolrQuery SolrQuery = Mockito.mock(SolrQuery.class);
private SolrDocumentList solrDocuments = Mockito.mock(SolrDocumentList.class);
private ShowService showService = Mockito.mock(ShowService.class);
#Test
public void findShowTest() {
Mockito.when(blogCoreSolrClient.query(solrQueryCaptor.capture())).thenReturn(queryResponse);
Mockito.when(queryResponse.getResults()).thenReturn(solrDocuments);
Mockito.when(blogCoreSolrClient.query(any())).thenReturn(queryResponse);
ShowService.Show showsResult = ShowService.findShow(ClientRegion.US, TargetLocale.EN_US, 1234);
assertThat(showsResult.pathValue).isEqualTo("shows/test/");
}
}
I am getting Null at blogCoreSolrClient when the code passes to findShow().
Because of that I am getting NullPointerException.
Any suggestions, where I might be going wrong. TIA
There are different problems :
You're mocking the class under test
private ShowService showService = Mockito.mock(ShowService.class);
You don't tell to your ShowService to use the blogCoreSolrClient mock, then the blogCoreSolrClient mock instance is created, but never used.
As you are using IOC to inject the SolrClient (#Resource annotation), you need to inject the mock in your ShowService instance during the test.
There are different solutions, but the more convenient in your case would be to use the Mockito Extension to perform the injection.
Something like :
#ExtendWith(MockitoExtension.class)
public class ShowServiceTest {
#Mock
private SolrClient blogCoreSolrClient;
... // Other mocks
#InjectMocks
private ShowService showService;
#Test
public void findShowTest() {
Mockito.when(blogCoreSolrClient.query(any())).thenReturn(queryResponse);
... // Complete test
}
}
The problem would be that your class under test is an abstract class.
I don't see any abstract method. So, if you really need the class under test to be abstract, then you'll face a technical difficulty with #InjectMocks.
Here are some solutions :
https://tedvinke.wordpress.com/2020/06/22/mockito-cannot-instantiate-injectmocks-field-the-type-is-an-abstract-class/
I'm new to writing tests in Java and trying to learn Mockito.
This is part of the class I want to test.
public class ExamRepository implements IExamRepository {
private static final Logger LOGGER = LogManager.getLogger(ExamRepository.class);
private IStudentRepository studentRepository = new StudentRepository();
private EntityManager entityManager;
public ExamRepository() {
entityManager = EntityController.getEntityManager();
}
public ExamRepository(EntityManager entityManager){
this.entityManager = entityManager;
}
// Get all exam skeletons from the DB
#Override
public List<ExamSkeleton> getAllSkeletons() {
try {
TypedQuery<ExamSkeleton> query = entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class);
return query.getResultList();
} catch (IllegalArgumentException exception) {
LOGGER.error(exception);
}
return Collections.emptyList();
}
}
This is the actual test I wrote, I have a feeling the error:
Argument passed to verify() is of type ExamRepository and is not a mock!
Is occurring because of this line:
examRepository = new ExamRepository(entityManager);
However I am uncertain as to how to rewrite it. I am also not sure what else I should be testing for except for the fact that it ran once.
public class ExamRepositoryTest {
#InjectMocks
private ExamRepository examRepository;
#Mock
private EntityManager entityManager;
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Test
public void canGetAllSkeletons(){
examRepository = new ExamRepository(entityManager);
List<ExamSkeleton> examSkeletons = new ArrayList<>();
examSkeletons.add(new ExamSkeleton());
examSkeletons.add(new ExamSkeleton());
TypedQuery query = mock(TypedQuery.class);
when(entityManager.createQuery(anyString(), Matchers.anyObject())).thenReturn(query);
when(query.getResultList()).thenReturn(examSkeletons);
verify(examRepository, times(1)).getAllSkeletons();
}
}
Hope you guys can put me on the correct track!
Use it like this:
#Test
public void canGetAllSkeletons(){
examRepository = new ExamRepository(entityManager);
List<ExamSkeleton> expected = new ArrayList<>();
expected.add(new ExamSkeleton());
expected.add(new ExamSkeleton());
TypedQuery query = mock(TypedQuery.class);
when(entityManager.createQuery(anyString(), anyObject())).thenReturn(query);
when(query.getResultList()).thenReturn(expected);
List<ExamSkeleton> result = examRepository.getAllSkeletons();
assertEquals(expected, result);
}
Your idea was almost correct, but instead of verifying a call, you just need to do the actual invocation of examRepository.getAllSkeletons() in your test and check the result against your expected return value for the TypedQuery.
And because you can only get the correct result list if your previous mocking steps worked, you don't need to verify any invocation on the EntityManager mock.
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 new to Mockito framework , I have a rest APi that connects my application to jasper server and do report related operations.I want to write junit test cases for rest API using mockito framework.
here i have class called Repositoryclient , Its constructor have instance of JasperServerInfo DAO class.
public class RepositoryClient {
public RepositoryClient(ServerInfo serverInfo) {
this.info = serverInfo;
try {
Session = Client.authenticate(info.username.trim(), info.password.trim());
}
catch (Exception e) {
}
}
public void Templates() { //this method brings list of present report in jasper server repository
try {
OperationResult<...> result = ....;
} catch (Exception e) {
INodeProcessor.logger.warn(e.toString());
throw Error.REPORT_TEMPLATE_LIST_ERROR.with();
}
}
So how to write JUnit test cases using mockito for this class please guide me through. Thank you in advance.
Well, the code could be improved to make it actually testable...
At the moment, there is no really good way to write unit tests for your code, since the constructor creates a JasperserverRestClient without any chance to change it. The least you can do is add another constructor (may be package access) to allow another JasperserverRestClient to be used. (Alternatively you could think about using a Factory pattern. but this might be to complicated.)
Then you could mock that...
JasperserverRestClient jasperServerClient = Mockito.mock( JasperserverRestClient.class );
RestClientSession session = Mockito.mock( RestClientSession.class );
Mockito.when( jasperServerClient.authenticate( "x", "y")).thenReturn( session );
RepositoryClient repositoryClient = new RepositoryClient(jasperServerClient);
This would at least allow you to test, that authenticate is called with the correct parameters via Mockito.verify.
Also it would allow you to test that the listTemplates method calls the session with the correct parameters (of course you'll need to so some more mocking there).
An additional constructor, assuming your tests are in the same package, would look like this:
RepositoryClient(JasperserverRestClient httpRestClient, JasperServerInfo serverInfo) {
this.info = serverInfo;
this.httpRestClient = httpRestClient;
try {
restClientSession = httpRestClient.authenticate(info.username.trim(), info.password.trim());
}
catch (Exception e) {
INodeProcessor.logger.warn(e.toString());
throw Error.REPOSITORY_CLIENT_ERROR.with();
}
}
This way you can inject a mocked instance of your JasperserverRestClient into your object.
A test of your listTemplates method would (addtionally) look like this...
X resourcesService = Mockito.mock( X.class ); // No clue what the resourcesService() method is supposed to return, fill that in here
Mockito.when ( restClientSession.resourcesService() ).thenReturn ( resourcesService );
...This will allow the part restClientSession.resourcesService() to work. Next...
Y resources = Mockito.mock( Y.class ); // Same thing here, don't know what resources() should return, insert that class here
Mockito.when( resourcesService.resources()).thenReturn ( resources );
This will allow the resources() call to work.
Next we do some trickery:
Mockito.when( resources.parameter( Mockito.anyString(), Mockito.anyString()).thenReturn(resources); // assuming that ResourceSearchParameter constant is a String
This will allow the parameter() calls to work by returning the same resources() object.
And so on... You will need to when(...).thenReturn(...) the search method to return a OperationResult<ClientResourceListWrapper>, etc. but that's the same stuff as above.
And in the end, we could verify that the methods were called with the right parameters...
Mockito.verify( resources, Mockito.times(1)).parameter(ResourceSearchParameter.FOLDER_URI, info.reportDirectory);
Mockito.verify( resources, Mockito.times(1)).parameter(ResourceSearchParameter.RECURSIVE, "false"
Mockito.verify( resources, Mockito.times(1)).search();
getting started example that i have :
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#Test(priority = 31, groups = "success")
public void mockExample() {
Category category1 = mock(Category.class);
when(category1.getName()).thenReturn("Yess!!!");
System.out.println(category1.getName());
}
will print:"Yess!!!"
you can read from here :
http://examples.javacodegeeks.com/core-java/mockito/mockito-hello-world-example/
#RunWith(SpringJUnit4ClassRunner.class)
public class UserControllerTest {
#InjectMocks
private UserController userController;
#Mock
private RequestAttributes attrubutes;
#Mock
private UserService userService;
private MockMvc mockMvc;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(attrubutes);
this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
}
#Test
public void getUserinfoDetails() {
String userId = "123";
String userName = "Test145";
List<UserDto> userDtoList = new ArrayList<>();
Mockito.when(userService.getAllUserInfo()).thenReturn(userDtoList);
Assert.assertNotNull(userController.getUserinfo());
Assert.assertNotNull(userDtoList);
Assert.assertNotNull(userId);
Assert.assertNotNull(userName);
}
#Test
public void getUserByIdDetails() {
String userId = "123";
UserDto userDto = new UserDto();
Mockito.when(userService.getUserByUserId(userId)).thenReturn(userDto);
Assert.assertNotNull(userController.getUserById(userId));
Assert.assertNotNull(userDto);
Assert.assertNotNull(userId);
}
}
===========================================================================
for reference use below link:(step by step explanation)
https://www.youtube.com/watch?v=yGLOexeJfKA&t=17s
I have a StoredProcedure which is compiled on initialization.
Occasionally the logic requires that I use a different stored procedure.
I have tried and failed to reset the name of the stored procedure. The data is still retrieved using the original stored procedure.
Is there a way to achieve this?
Here is a reduced version of the class showing initialization and attempted recompiling with the name of a different stored procedure:
import org.springframework.jdbc.object.StoredProcedure;
public class MyDAOImpl extends StoredProcedure implements MyDAO {
#Autowired
public MyDAOImpl(DataSource dataSource, String originalSPName) {
super(dataSource, originalSPName); // invokes StoredProcedure constructor
compile();
}
public List<String> useOtherStoredProcedure(){
super.setSql("otherSPName");
compile();
// Error: Data is still retrieved with original StoredProcedure name
Map<String, Object> data = this.executeSP();
}
}
Rather than org.springframework.jdbc.object.StoredProcedure pls use org.springframework.jdbc.core.simple.SimpleJdbcCall. The beauty of SimpleJdbcCall is that you can dynamically specify the schema, package and stored procedure names. Pls find the respective code below :-
#Autowired
private JdbcTemplate jdbcTemplate;
public Date getSPData() {
SimpleJdbcCall spCall = new SimpleJdbcCall(jdbcTemplate).withSchemaName("schema")
.withCatalogName("catalog")
.withProcedureName("proc")
.withoutProcedureColumnMetaDataAccess()
.useInParameterNames("ref_id")
.declareParameters(
new SqlParameter("ref_id", Types.NUMERIC),
new SqlOutParameter("dt", Types.DATE));
SqlParameterSource in = new MapSqlParameterSource()
.addValue("ref_id", 12345);
Map<String, Object> out = spCall.execute(in);
Date date = (Date) out.get("dt");
return date;
}
I believe this might be what you want:
public class MyDAOAdapter implements MyDAO {
private volatile MyDAO currentDao;
private final MyDAO myDAOImpl1;
private final MyDAO myDAOImpl2;
#Autowired
public MyDAOImpl(#Qualifier("myDAOImpl1") MyDAO myDAOImpl1, #Qualifier("myDAOImpl2") MyDAO myDAOImpl2) {
this.myDAOImpl1 = myDAOImpl1;
this.myDAOImpl2 = myDAOImpl2;
currentDao = myDAOImpl1;
}
public void switchToFirstDao() {
currentDao = myDAOImpl2;
}
public void switchToSecondDao() {
currentDao = myDAOImpl2;
}
// do you really need this?
public List<String> useOtherStoredProcedure(){
return myDAOImpl2.executeSP();
}
// Delegate all the methods to current DAO selected
public List<String> executeSP(){
return currentDao.executeSP();
}
// implement all other methods by delegating calls to currentDao
}
This should be autowired by all the code and the switch between the two StoredProcedure implementations would be hidden inside this adapter. Still I didn't understand if you want this switch to be global for all code or only for some cases.
The solution I found for my own situation was to implement a third stored procedure on SQL Studio, which acts as a common accessor and routes the query to the right stored procedure based on a parameter.
CREATE PROCEDURE [dbo].[Router_SP]
#spNumber as INTEGER
AS
BEGIN
IF(#spNumber = 1) EXECUTE originalSPName
ELSE IF (#spNumber = 2) EXECUTE otherSPName
ELSE RETURN 'Unrecognised stored procedure'
END
Leaving this question open for now to see if a better solution comes up.