Junit for SimpleJdbcCall with JdbcTemplate Autowired - spring

How do i test the repository class which uses JdbcTemplate and SimpleJdbcCall as below
This is what i have tried
Below is the test code and repository code
I am using Spring boot latest version junit 5 and mockito.
I have tried looking into the below solution but could got it working
Mockito for SimpleJdbcCall with Spring JdbcTemplate
#RunWith(MockitoJUnitRunner.class)
public class DataRepositoryTest {
#InjectMocks
private DataRepository dataRepository
#Mock
private JdbcTemplate oracleJDBCTemplate;
#Mock
private SimpleJdbcCall simpleJdbcCall;
#BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
simpleJdbcCall = new SimpleJdbcCall(oracleJDBCTemplate)
.withProcedureName("PROC_NAME_P1")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(
new SqlParameter("p_in_name", Types.VARCHAR),
new SqlParameter("p_age", Types.VARCHAR)
).returningResultSet("ref_cur", new DataRowMapper());
}
#Test
public void test()
{
System.out.println(" JdbcTemplate-- " + oracleJDBCTemplate ); // prints is oracleJDBCTemplate;
System.out.println(" simpleJdbcCall-- " + simpleJdbcCall ); //print object hascode
}
}
Below is the repository code
#Repository
public class DataRepository{
#Autowired
#Qualifier("OracleJDBCTemplate")
private JdbcTemplate oracleJDBCTemplate;
private SimpleJdbcCall simpleJdbcCall;
#PostConstruct
public void init()
{
simpleJdbcCall = new SimpleJdbcCall(oracleJDBCTemplate)
.withProcedureName("PROC_NAME_P1")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(
new SqlParameter("p_in_name", Types.VARCHAR),
new SqlParameter("p_age", Types.VARCHAR)
).returningResultSet("ref_cur", new DataRowMapper());
}
#SuppressWarnings("unchecked")
public List<Person> getPerson(Data data) {
Map<String, Object> result =
simpleJdbcCall.execute(date.getName,date.getAge);
return (List<Person>) result.get("ref_cur");
}
}

Seems like you're mixing JUnit 4 and JUnit Jupiter (part of JUnit 5) here.
#RunWith is JUnit 4 (JUnit Jupiter equivalent is #ExtendWith(MockitoExtension.class)
#BeforeEach is JUnit Jupiter
Furthermore don't manually initialize your simpleJdbcCall when you want to have a mock of it. When writing a unit test for your DataRepository and let Mockito create the class under test for you, #PostConstruct won't be called, so it's fine to mock all collaborators.
The following setup will mock your and you can use Mockito's when().thenReturn() to define the behavior of your mocks:
#ExendWith(MockitoExtension.class)
public class DataRepositoryTest {
#InjectMocks
private DataRepository dataRepository
#Mock
private JdbcTemplate oracleJDBCTemplate;
#Mock
private SimpleJdbcCall simpleJdbcCall;
#Test
void test() {
}
}

Related

Not able to mock jdbcTemplate(datasource) in springboot test class using testNG

I am getting a null pointer exception on jdbcTemplate object in this MyMain.java class while mocking the jdbcTemplate.update() method. I have used #Mock for this in the MyMainTest.java class. Here are my code snippets:
MyMain.java
#Component
public class MyMain {
private JdbcTemplate jdbcTemplate;
#Autowired
#Qualifier("myDatasource")
Datasource myDatasource;
#PostConstruct
public void initialize() {
jdbcTemplate = new JdbcTemplate(myDatasource);
}
public void saveData() {
jdbcTemplate.update("query", "parameter passing here"); // In this line only I am getting Nullpointer exception on jdbcTemplate.
}
}
MyMainTest.java
public class MyMainTest {
#Mock
JdbcTemplate jdbcTemplate;
#Test
public void saveDataTest() {
when(jdbcTemplate.update(Mockito.any(), Mockito.any()).thenReturn(1);
new MyMain().saveData();
}
}
I have tried several alternative ways and I am still getting this issue.
Note: I am using TestNG for running the test classes. It's a Spring Boot project.

How to inject MockMvc with multiple objects in Spring Boot REST Junit test case

I have a SpringBoot REST API connecting to Oracle DB.
My controller calls BusinessImpl layer and in-turn BusinessImpl calls multiple DAO layers (Controller -> BusinessImpl -> DAO1, DAO2, DAO3)
The below test case works perfectly
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration()
#TestPropertySource("classpath:dev-manifest.yml")
#ContextConfiguration(classes = Application.class)
#ConfigurationProperties(prefix = "env")
#SpringBootTest
public class MyTest
{
private static final String REQUEST_URI = "/v1/registration/accounts/links";
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup()
{
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void testSave()
{
String testInput = "some json input";
mockMvc.perform(post(REQUEST_URI).content(testInput).contentType(contentType))
.andExpect(status().isOk());
}
But I do not want to hit real database during junit test case. So I wrote a mock.
Working Code
#Mock
private SecurityAuditDAO securityAuditDAO;
#InjectMocks
private RegistrationBusinessImpl registrationBusinessImpl;
#Test
public void testSave()
{
when(securityAuditDAO.getState(Mockito.any())).thenReturn("somestring");
SomeRequest someRequest = new SomeRequest();
someRequest.setStatus("SUCCESS");
SomeResponse status = registrationBusinessImpl.createUser(SomeRequest, "127.0.0.1");
}
The above code worked perfectly. In businessImpl class securityAuditDAO.getState returned "somestring". But when I introduced mockMvc.perform it stopped working.
Not Working
#Test
public void testSave()
{
when(securityAuditDAO.getState(Mockito.any())).thenReturn("somestring");
String testInput = "some json input";
mockMvc.perform(post(REQUEST_URI).content(testInput).contentType(contentType))
.andExpect(status().isOk());
}
The above code was still hitting the database. So I realized that I should inject mockMvc with securityAuditDAO so I added the following line
this.mockMvc = MockMvcBuilders.standaloneSetup(securityAuditDAO).build();
Code
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private SecurityAuditDAO securityAuditDAO;
#InjectMocks
private RegistrationBusinessImpl registrationBusinessImpl;
#InjectMocks
RegistrationApiController registrationApiController;
#Before
public void setup()
{
MockitoAnnotations.initMocks(this);
//this.mockMvc = webAppContextSetup(webApplicationContext).build();
this.mockMvc = MockMvcBuilders.standaloneSetup(securityAuditDAO).build();
//this.mockMvc = MockMvcBuilders.standaloneSetup(registrationApiController).build();
//ReflectionTestUtils.setField(mockMvc, "securityAuditDAO", securityAuditDAO);
}
I tried injecting securityAuditDAO. But if I do that, my other autowired instances in BusinessImpl were null.
How to inject securityAuditDAO without affecting others or how to inject both webApplicationContext and securityAuditDAO.
Also tried ReflectionTestUtils.setField but it didn't work as expected.

JUnit not working in Spring Boot with #Autowired annotation

I have a Spring Boot application in which I'm creating REST web services
using the MVC pattern.
I have a controller, service and DAO class and I use the #Autowired annotation for calling methods of the service and DAO layer.
When I create JUnit tests using mockito, the values are going into the controller but from the controller they are not going to the service class.
Here is the code sample:
#WebAppConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {AppplicationConfiguration.class})
public class ExternalControllerTest {
private MockMvc mockMvc;
#InjectMocks
private MyController myController;
#MockBean
myService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.build();
}
#Test
public void testListCluster() throws Exception {
Input emrInput = new Input();
emrInput.setId("200004773");
emrInput.setName("test");
String expected = "{\"status\":\"Success\",\"message\":\"Success\",\"data\":\"somevalue\"}";
AutomateRestResponse response = new AutomateRestResponse<JsonObject>();
response.setMessage("Success");
response.setStatus("Success");
response.setData("somevalue");
Mockito.when(
externalService.listCluster(emrInput)
).thenReturn(response);
mockMvc.perform(post("/v1/gerData"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("Success")));
verify(externalService, times(1)).listCluster(emrInput);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/v4/listCluster")
.accept(MediaType.APPLICATION_JSON).content(emrInputJosn)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println("response body1" + result.getResponse()
.getContentAsString());
}`
Please help me with this.
It is not clear from your question what you are trying to mock.
Anyway, you should not be able to debug your service/dao that is mocked since what actually executed in the test is the mocked one and not yours.
If you want to test your controller, you can mock your service or dao and define what the response they will return, and then verify that the response you get from your controller is as you expect it to be.
#EnableWebMvc
#SpringBootApplication(scanBasePackages = { "com.yourPackage.external" })
public class YourApplication extends org.springframework.boot.web.support.SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<Application> applicationClass = Application.class;
}
Based on what you have pasted, you can do below things:
if you are using #RunWith(SpringJUnit4ClassRunner.class) [better change to #RunWith(SpringRunner.class)] then use
#MockBean
private MyService externalService;
OR
use #RunWith(MockitoJUnitRunner.class) and
#MockBean
private MyService externalService;
#InjectMocks
private MyController controller = new MyController(externalService);
for details checkout :- testing web in spring boot
#WebAppConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {AppplicationConfiguration.class})
public class ExternalControllerTest {
private MockMvc mockMvc;
#InjectMocks
private MyController myController ;
#MockBean
myService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.build();
}
#Test
public void testListCluster() throws Exception {
Input emrInput = new Input();
emrInput.setId("200004773");
emrInput.setName("test");
String expected = "{\"status\":\"Success\",\"message\":\"Success\",\"data\":\"somevalue\"}";
AutomateRestResponse response = new AutomateRestResponse<JsonObject>();
response.setMessage("Success");
response.setStatus("Success");
response.setData("somevalue");
Mockito.when(
externalService.listCluster(emrInput)
).thenReturn(response);
mockMvc.perform(post("/v1/gerData"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("Success")));
verify(externalService, times(1)).listCluster(emrInput);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/v4/listCluster")
.accept(MediaType.APPLICATION_JSON).content(emrInputJosn)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println("response body1"+ result.getResponse()
.getContentAsString());
}
}

Not able to mock jdbcTemplate in Spring boot Test class

I am using Spring boot and Mockito for testing. I have been able to write test cases for Service layer and they re working fine. But, the test cases for DAO layer do not. The jdbcTemplate object that is mocked and autowired gives null pointer when executing the test case. Below are the details:
My DAOTest class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = EcommerceApplication.class)
public classEcommerceDaoTest {
#InjectMocks
private IEcommerceDao ecommerceDao = new EcommerceDaoImpl();
#Mock
#Autowired
private JdbcTemplate as400JdbcTemplate;
#Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
}
#Test
public void checkOrderExistsTest() throws EcommerceException{
Mockito.when(as400JdbcTemplate.queryForObject(queryForOrder,new Object[]
{"1000"}, int.class)).thenReturn(1);
boolean exists =
ecommerceDao.checkOrderExists("1000");
assertTrue(exists);
}
}
EcommerceDAOImpl.java:
#Override
public boolean checkOrderExists(String orderNo)throws EcommerceException{
boolean doesExist = false;
int count = 0;
try{
count= as400JdbcTemplate.queryForObject(queryForOrder, new Object[]{orderNo}, int.class);
if(count >0){
doesExist = true;
}
}
catch(Exception e){
}
return doesExist;
}
AS400Config.java:
#Bean
#Autowired
public JdbcTemplate as400JdbcTemplate(#Qualifier("as400DataSource")DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
ECommerceApplication.java
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
#EnableTransactionManagement
#Import(As400Configuration.class)
public class EcommerceApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceApplication.class, args);
}
}
When I am running the test case, I am getting NullPointerException for as400JdbcTemplate. The functionality works fine as is. Its just the test cases for DAO layer that fail because of the inability of the jdbcTemplate to get mocked/autowired.
Please let me know where I am going wrong.
You don't need to use #Mock and #Autowired at the same time. Use only #Mock:
#Mock
private JdbcTemplate as400JdbcTemplate;
Use instead of #RunWith(SpringRunner.class) --> #RunWith(MockitoJUnitRunner.class)
Also to inject mock into DAO you can use ReflectionTestUtils from spring test.
public static void setField(Class targetClass, String name, Object value)
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(ecommerceDao ,"as400JdbcTemplate" ,
as400JdbcTemplate);
}
#Mock
private JdbcTemplate as400JdbcTemplate;

Using #SpyBean with #Qualifier Spring Boot Test

I have 2 DataSources in my app.
So, to get the required JdbcTemplate, i use #Qualifier. But, when i do like below, the test runs... but stays waiting indefinitely, if there is any use of JdbcTemplate in the "Method Under Test".
#Service
#Transactional
public class SampleDatabaseService {
#Autowired
#Qualifier("firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;
#Autowired
#Qualifier("secondDbJdbcTemplate")
private JdbcTemplate secondDbJdbcTemplate;
#Cacheable("status")
public Map<String, Device> readAllValidDeviceStatus() {
Map<String, Device> allDeviceStatuses = new HashMap<>();
//Stops at below line indefinitely if "SpyBean" is used
List<StatusDetail> statusDetails = firstDbJdbcTemplate
.query(SqlQueries.READ_DEVICE_STATUS, BeanPropertyRowMapper.newInstance(StatusDetail.class));
statusDetails
.stream()
.filter(deviceStatus -> deviceStatus.getName() != "Some Invalid Name")
.forEach(deviceStatus -> allDeviceStatuses
.put(deviceStatus.getName(), buildDevice(deviceStatus)));
return allDeviceStatuses;
}
/** More Stuff **/
}
and the Test :
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Transactional
#Rollback
#ActiveProfiles("test")
public class SampleDatabaseServiceTest {
#SpyBean
#Qualifier("firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;
#Autowired
private SampleDatabaseService serviceUnderTest;
#Before
public void populateTables() {
//Insert some Dummy Records in "InMemory HSQL DB" using firstDbJdbcTemplate
}
#Test
public void testReadAllValidDeviceStatus() {
// When
Map<String, Device> allDeviceStatuses = serviceUnderTest.readAllValidDeviceStatus();
// Then
assertThat(allDeviceStatuses).isNotNull().isNotEmpty();
// More checks
}
/* More Tests */
}
But, when i replace the #SpyBean with #Autowired in Test, it works fine.
Why is it so? Any help is greatly appreciated. :)
Use it in below format
#MockBean(name = "firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;

Resources