How to test DaoImpl methods using Junit and Mockito - spring

I am using spring with jdbcTemplate for my app and I want to test DaoImpl class. There is implementation for insertion, updation and retrieval operation
Dao class Method
//dummy class
public class PlayerDAOImpl implements PlayerDAO {
#Autowired
private JdbcTemplate jdbcTemplate;
public Integer getPlayer(int playerId) {
String sql = "SELECT ccount(1) FROM PLAYER WHERE
PLAYER_ID = ?";
return (jdbcTemplate. queryForObject("Query", new Object[]{playerId},
Integer.class)!=0); //here only throws exception
}
//other methods
}
and for that I have written Test class which execute successfully for insertion and updation but while retrieving it is giving nullpointer exception.
#RunWith(MockitoJUnitRunner.class)
class Test{
#InjectMocks
PlayerDAOImpl dao;
#Mock
JdbcTemplate jdbcTemplate;
#Test
public void retrieveResult(){
Mockito.when(dao.getPlayer(int playerId)).thenReturn(false);
//Assert Statement
}}
I have googled/tried but not found solution which worked for me. So how to test that method or inject jdbcTemplate so that it will succeed.
Thanks for Help!!

The problem is that you are trying to mock the class under test (PlayerDAOImpl) instead of its dependency (JdbcTemplate).
Change you mock to something like:
Mockito.when(jdbcTemplate.queryForObject(Mockito.any(), Mockito.any(), Mockito.any()).thenReturn(COUNT);
Where COUNT is an Integer, and then write your assertions on the return value of dao.getPlayer.

Related

JUnit 5/Spring Boot - Use Properties but Mock Dependencies

I'm trying to write unit tests for a DAO/Repository. My intent is to mock the NamedParameterJdbcTemplate object within and verify that the surrounding business logic doesn't do any bad (i.e.: handles nulls, etc...).
I'd also like to verify that the SQL is combined correctly. I can do this with doAnswer(...), but the SQL queries live in a .properties file.
Is there a way to load a .properties file for testing, without loading all of the other dependencies of this class?
What I've Tried
I've tried decorating the Test class with various permutations of :
#ExtendWith(SpringExtension.class)
#ExtendWith(MockitoExtension.class)
#ContextConfiguration(classes = WidgetRepositoryImpl.class)
#TestPropertySource(properties = "sql.properties")
However, turning these on and off always seems to have one of the following effects:
Load the NamedParameterJdbcTemplate as a bean. This could work if I specified the nearby AppConfig class in the ContextConfiguration annotation, but then I'd need to load all of its underlying dependencies, and the whole point is to mock this field.
Load the Repository and mock the NamedParameterJdbcTemplate, but not load sql.properties. The SQL statements are now null.
I want to avoid ReflectionTestUtils.setField(widgetRepository, "namedParameterJdbcTemplate", "<put the sql here>"). This works, but there are many SQL queries (the code below is very simplified). It also introduces a risk of human error (since now we're testing strings in the Test class, not the actual properties file.
The question
Is there any way to load sql.properties for this class, but not attempt to load the NamedParameterJdbcTemplate?
Unit Test
#ExtendWith(SpringExtension.class)
#TestPropertySource(properties = "sql.properties")
class WidgetRepositoryImplTest {
#Mock
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Autowired
private WidgetRepository widgetRepository;
#Test
public void testGetWidgetById() {
// build a mock that returns a fake widget, and stores the SQL string for other tests
doAnswer(invocation -> { ...omitted for brevity... }).when(namedParameterJdbcTemplate).query(anyString(), anyMap(), any(WidgetMapper.class));
Widget widget = widgetRepository.getWidgetById("asdf-1234");
assertNotNull(widget);
}
Repository
#PropertySource("classpath:sql.properties")
#Slf4j
#Repository
public class WidgetRepositoryImpl implements WidgetRepository {
#Value("${widget-sql.selects.select-widget-by-id}")
private String selectWidgetByIdQuery;
#Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Override
public Widget getWidgetById(String id) {
Map<String, String> params = new HashMap<>();
params.put("widgetId", id);
List<Widget> results = namedParameterJdbcTemplate.query(selectWidgetByIdQuery, params, new WidgetMapper());
if (results.isEmpty()) {
return null;
}
return results.get(0);
}
sql.properties
widget-sql.selects.select-widget-by-id=select * from [WIDGETS] where WIDGET_ID=:widgetId
# a few dozen additional queries in here
The solution is to use SpringExtension with the #MockBean annotation. This annotation will generate a mock implementation of the given class and provide it as a Spring bean. This means that if your class uses #Autowired, Spring will inject the mock for you:
#ExtendWith(SpringExtension.class) // Make sure to use SpringExtension
#TestPropertySource(properties = "sql.properties")
class WidgetRepositoryImplTest {
#MockBean // Replace #Mock with #MockBean
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Autowired
private WidgetRepository widgetRepository;
// ...
}

Junit Test using SpringJUnit4ClassRunner

I am trying to create junit test case using SpringJUnit4ClassRunner.
#Configuration
#ComponentScan(basePackages = { "com.controller",
"com.service",
"com.repository" })
class CustomConfiguration {
}
#RunWith(SpringJUnit4ClassRunner.class)
#org.springframework.test.context.ContextConfiguration(classes = CustomConfiguration.class)
public class Test {
#InjectMocks
#Spy
private EmployeeController employeeController;
#Mock
EmployeeService employeeService;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
#org.junit.Test
public void test() throws Exception {
Employee employee = new Employee();
employee.setEmailId("admin#gmail.com");
employee.setFirstName("admin");
employee.setLastName("admin");
Employee employee = employeeController.createEmployee(employee);
assertNotNull(employee);
}
}
It is giving error of No qualifying bean of type EmployeeRepository.
It seems that even tough you are having a custom configuration class for your test, the repository beans are not getting created in background through classpath scanning. If you are aiming for an integration test case rather than a junit one since you doesn't seem to mock anything in the code that you provided , why don't you try using more updated annotation version like using SpringRunner.class instead of SpringJunit4Runner.class , if your spring version supports it. If you are just aiming to create a unit test case. Create a mock bean for whatever you want to mock like :
#Mock
SomeRepository repo;
This mock should be automatically injected to your service beans when it starts up by junit.
If you are on springboot then:
#RunWith(SpringRunner.class)
#SpringBootTest
public class Test {
#Mock
EmployeeService employeeService;
#InjectMocks
private EmployeeController employeeController;
#org.junit.Test
public void test() throws Exception {
Employee employee = new Employee();
employee.setEmailId("admin#gmail.com");
employee.setFirstName("admin");
employee.setLastName("admin");
when(employeeService.save(any)).thenReturn(employee);
Employee employee = employeeController.createEmployee(employee);
assertNotNull(employee);
}
}
The above is a typical example for unit test in springboot , but in your case for controller classes springboot provides the annotation #WebMvcTest or unit testing the web layer only.If you want to do it like that , read doc.

How to Mock jdbcTemplate.getJdbcTemplate().execute(); method?

My question is how to mock
jdbcTemplate.getJdbcTemplate().execute("TRUNCATE table TABLE_1");
method?
It's return value is void if I am right.
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Mock
private NamedParameterJdbcTemplate jdbcTemplate;
...
//I tried this but of course it doesn't work
doReturn(void).when(jdbcTemplate).getJdbcTemplate().execute("TRUNCATE TABLE TABLE_1");
Any help is welcome.
From the comments, my understanding is that getJdbcTemplate is not final and you're interested in mocking its return value so you can verify method calls.
Here's the approach I'd take:
// create a mock for the return value
#Mock
JdbcTemplate template;
// create a mock for the factory
#Mock
NamedParameterJdbcTemplate jdbcTemplate;
#Before
public void setUp() {
// other initializations here
// configure the factory to return the above mocked template
when(jdbcTemplate. getJdbcTemplate()).thenReturn(template);
}
Now you should be able to verify on the template mock:
verify(template).execute("TRUNCATE TABLE TABLE_1");

Mockito test coming back as zero

I am trying to get call method called totalmoney() to get the total money in the h2 database but it always returns 0.
#RunWith(MockitoJUnitRunner.class)
public class MoneyTests {
#InjectMocks
MoneyServiceImplementation MoneyServiceImplementation;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void getAllMoney() {
long total_money = MoneyServiceImplementation.TotalMoney();
assertEquals("2000", total_money);
}}
But it will return the right amount of 2000 by:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Bean.xml");
MoneyService MoneyService = (MoneyService) context.getBean("MoneyServiceImplementation");
long total_money = MoneyService.TotalMoney();
So what am i doing wrong in the test that it will not work?
Mockito is not an dependency injection framework, don't expect this shorthand utility to inject a complex graph of objectsbe it mocks/spies or real objects.
Again, note that #InjectMocks will only inject mocks/spies created using the #Spy or #Mock annotation.
There are no any #Mock or #Spy annotated beans in your test, so all of the dependencies in the created MoneyServiceImplementation are null.

CrudRepository test cases without inserting data in DB

I have one repository class which which implements CrudRepository. Then in service class I have auto wired this repositary. Then in controller class I have autowired this service.
I want to write test cases of controller Class. I am using below configuration.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class XYZControllerTest {
MockMvc mockMvc;
#Mock
private XYZController xyzController;
#Autowired
private TestRestTemplate template;
#Autowired
XYZRepository xyzRepository;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(xyzController).build();
}
#Test
public void testPanelShouldBeRegistered() throws Exception {
HttpEntity<Object> xyz = getHttpEntity("{\"name\": \"test 1\", \"email\": \"test10000000000001#gmail.com\","
+ " \"registrationNumber\": \"41DCT\",\"registrationDate\":\"2018-08-08T12:12:12\" }");
ResponseEntity<XYZ> response = template.postForEntity("/api/xyz", xyz, XYZ.class);
}
}
My problem is that when I run test case, data is going to insert in DB which is used for application. Can I test it without inserting data in DB.
Conceptually when we are testing services we mock repositories instead of injection.
You need to mock your repository and setup behavior for returning data.
An example :
#MockBean
XYZRepository xyzRepository;
#Test
public void test() {
// other mocks
//
when(xyzRepository.findAll()).thenReturn(Arrays.asList(new XYZ()));
// service calls
// assertions
}

Resources