Im trying to write the Unit test for a Create(Post) method which uses the JPA as DAO Layer .Im new to Mockito , hence insights needed .
1.EmployeeService .java
#Component("IEmployeeService ")
public class EmployeeService implements IInputService {
#Inject
EntityManagerFactory emf;
#PersistenceContext
EntityManager em;
public InputEntity create(InputEntity inputEntity) {
em = emf.createEntityManager();
try {
em.getTransaction().begin();
inputEntity.setLST_UPDTD_TS(new Date());
inputEntity.setLST_UPDTD_USER_ID(new String("USER1"));
em.persist(inputEntity);
em.getTransaction().commit();
} catch (PersistenceException e)
{
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw new WebApplicationException(e,Response.Status.INTERNAL_SERVER_ERROR);
}
finally {
em.close();
}
return inputEntity;
}
2.InputEntity.java is the Entity class with getters and setters for corresponding columns to employee age,salary ,etc .
Now if a Post method is called ,the create method in the EmployeeService class will be invoked .I have to write a unit test using mockito , and i m getting null-pointer , below is the test i wrote .
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceTest {
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
#Autowired
EmployeeService employeeService;
#Mock
InputEntity inputEntity;
#Mock
EntityManagerFactory emf;
#Mock
private EntityManager em;
#Mock
private EntityTransaction et;
#Rule
public ExpectedException expectedException = ExpectedException.none();
#Test
public void test_create_employee_success() throws Exception {
InputEntity expected = Mockito.mock(InputEntity .class);
Mockito.when(em.getTransaction()).thenReturn(et);
Mockito.when(emf.createEntityManager()).thenReturn(em);
Mockito.doReturn(expected).when(employeeService).create(inputEntityMock);
InputEntity actual = new InputEntity();
Mockito.doReturn(actual).when(employeeService).create(inputFileRoleValidationMock);
assertEquals(expected, actual);
}
You have a local mock expected, that you are attempting to use in an assertEquals(), but that will never work because assertEquals uses Object.equals, and Mockito hijacks equals for internal uses. A Mockito mock will never Object.equals anything except itself.
We had the similar problem of NullPointerException and it was because of the entity manager. After we updated the connection properties in setUp method, we could able to call the JPA.
You can try to set the connection properties something like this.
//declare emfactory
private static EntityManagerFactory emfactory;
private static EntityManager em;
#BeforeClass
public static void setUp() throws Exception{
Map<Object, Object> properties = new HashMap<Object, Object>();
properties.put("openjpa.ConnectionURL",
"jdbc:db2://yourserver:port/DBName");
properties.put("openjpa.ConnectionUserName", "username");
properties.put("openjpa.ConnectionPassword", "userpassword");
//set Schema
//set Driver Name
emfactory = Persistence.createEntityManagerFactory("PersistenceUnitName",
properties);
em = emfactory.createEntityManager();
Mockito.when(emf.createEntityManager()).thenReturn(em);
}
Plus you need to modify your test_create_employee_success() to make this working. You are mocking everything in this method, which you should not do. You can try something like this.
#Test
public void test_create_employee_success() throws Exception {
{
InputEntity inputEntity = new InputEntity();
employeeService.create(inputEntity);
}
You need following changes in the code:
1.Instead of
#Autowired
EmployeeService employeeService;
You can use:
#InjectMocks
private EmployeeService EmployeeService;
Also as you are mocking in the method - InputEntity expected = Mockito.mock(InputEntity .class); you dont need at this declaration at the class level unless it is used in some other methods.
Also you can get rid of the declaration -
InputEntity actual = new InputEntity();
You can not assert mocked object and object using new keyword for equality.
Clean unit test will look like this -
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceImplTest {
#Mock
private EntityManager em;
#Mock
private EntityManagerFactory emf;
#InjectMocks
private EmployeeService EmployeeService;
#Mock
private EntityTransaction et;
#Test
public void testCreate() throws Exception {
InputEntity expected = Mockito.mock(InputEntity.class);
Mockito.when(em.getTransaction()).thenReturn(et);
Mockito.when(emf.createEntityManager()).thenReturn(em);
EmployeeService.create(expected);
Mockito.verify(em, Mockito.times(1)).persist(expected);
}
}
Related
I am having dificulties with using MockMvc.
Here I have simple Service and controller classes:
Service:
#Slf4j
#Service
public class EmployeeService {
//...
public Employee GetSample() {
//...
//filling Employee Entities
return new Employee(
"Harriet"
, "random"
, 25);
}
}
controller:
#RestController
#RequestMapping(value = "/info")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#Validated
public class EmployeeController {
private final EmployeeService employeeService;
#PostMapping("/GetEmployee")
public ResponseEntity<Employee> GetEmployee() {
Employee employee = employeeService.GetSample();
return new ResponseEntity<>(employee, HttpStatus.OK);
}
}
Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeTestCase {
private MockMvc mockMvc;
#InjectMocks
private EmployeeController EmployeeController;
#Mock
private EmployeeService employeeService;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(employeeController).build();
}
#Test
public void getEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/info/GetEmployee")).andDo(print());
}
}
when I try to use MockMvc I get null body. It seems employee is null. But I didn't understand why.
I thought that when test uses perform, it should initialise employee and later on it should't be null.
I tried to cut the code as much as possible. I hope it is not long.
Note : also tried to use Mockito.when(employeeController.GetEmployee()).thenCallRealMethod();
The #SpringBootTest annotation loads the complete Spring application
context. That means you do not mock your layers
(Services/Controllers).
If you wanted to test specific layers of your application, you could look into test slice annotations offered by Springboot: https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html
In contrast, a test slice annotation only loads beans required to test a particular layer. And because of this, we can avoid unnecessary mocking and side effects.
An example of a Test Slice is #WebMvcTest
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = HelloController.class,
excludeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void hello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
#Test
public void helloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount)));
}
}
However if you really wanted to load up the SpringBoot Application context, say for an Integration Test, then you have a few options:
#SpringBootTest
#AutoConfigureMockMvc
public class TestingWebApplicationTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class AuctionControllerIntTest {
#Autowired
AuctionController controller;
#Autowired
ObjectMapper mapper;
MockMvc mockMvc;
#Before
public void setUp() throws Exception {
System.out.println("setup()...");
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void create_ValidAuction_ShouldAddNewAuction() throws Exception {
final Auction auction = new Auction(
"Standing Desk",
"Stand up desk to help you stretch your legs during the day.",
"Johnnie34",
350.00);
mockMvc.perform(post("/auctions")
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(auction)))
.andExpect(status().isCreated());
}
}
Lets say you don't want to load up any layers at all, and you want to mock everything, such as for example a Unit Test:
#RunWith(MockitoJUnitRunner.class)
class DemoApplicationTest {
#Mock
private UserRepository userRepository;
private Demo noneAutoWiredDemoInstance;
#Test
public void testConstructorCreation() {
MockitoAnnotations.initMocks(this);
Mockito.when(userRepository.count()).thenReturn(0L);
noneAutoWiredDemoInstance = new Demo(userRepository);
Assertions.assertEquals("Count: 0", noneAutoWiredDemoInstance.toString());
}
}
Hi I have a service class that contains mapper and repository:
#Service
public class ProductServiceImp implements ProductService {
#Autowired
private ProductRepository repository;
#Autowired
private WarehouseApiMapper mapper;
public ProductServiceImp(ProductRepository repository) {
this.repository = repository;
}
}
Repository:
#Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
Mapper:
#Mapper(componentModel = "spring")
public interface WarehouseApiMapper {
WarehouseApiMapper mapper = Mappers.getMapper(WarehouseApiMapper.class);
Product ProductDtoToProduct(ProductDto productDto);
ProductDto ProductToProductDto(Product product);
}
In test class I would like to inject mock repository and autowired mapper
Here is my test class:
#SpringBootTest
public class ProductServiceTest {
#Mock
ProductRepository repository;
#InjectMocks
ProductServiceImp service;
#ParameterizedTest
#MethodSource("provideParametersProductUpdate")
void assert_that_product_is_updated_correctly(String productName, BigDecimal productPrice) {
Product oldProduct = new Product("Product that does not exist", BigDecimal.valueOf(1000000), null);
oldProduct.setId(1);
Mockito.when(repository.findById(1)).thenReturn(Optional.of(oldProduct));
Product newProduct = new Product(productName, productPrice, null);
newProduct.setId(1);
ProductDto updatedProduct = service.updateProduct(newProduct);
Assertions.assertEquals(productPrice, updatedProduct.getPrice());
Assertions.assertEquals(productName, updatedProduct.getName());
}
private static Stream<Arguments> provideParametersProductUpdate() {
return Stream.of(
Arguments.of("dark chocolate", BigDecimal.valueOf(3.2)),
Arguments.of("chewing gum", BigDecimal.valueOf(1.2)),
Arguments.of("lollipop", BigDecimal.valueOf(4.0))
);
}
}
Code throws NullPointerException when is trying to map object in service method.
Somebody knows how can I inject this? Thanks for ur answers
If you want to create just a Mockito test you could use the annotation #RunWith(MockitoJUnitRunner.class) instead of #SpringBootTest.
But if you want to create a Spring Boot integration test then you should use #MockBean instead of #Mock and #Autowired instead of #InjectMocks.
I use spring boot 2.3.2 with mapstruct.
In a service class I have a mapper who have an autowired annotation.
#Service
public BillingService{
private BillingRepository billingRepository;
#Autowired
private BillingMapper billingMapper;
#Autowired
public BillingService (BillingRepository billingRepository){
this.billingRepository=billingRepository;
}
public void getBilling(Long billingId){
....
billingMapper.convertTo(...);
}
}
#RunWith(MockitoJUnitRunner.class)
public class BillingServiceTest{
#Mock
BillingRepository billingRepository;
private BillingService bilingService;
#Spy
private BillingMapper billingMapper = Mappers.getMapper(BillingMapper.class);
#BeforeEach
public void setup(){
MockitoAnnotations.initMocks(this);
billingService = new BillingService();
}
#Test
public void testGetBilling(){
List<Billing> billings = new ArrayList<>();
...
List<BillingPayload> payloads = new ArrayList<>();
when(billingMapper.convertTo(billings)).thenReturn(payloads);
bilingService.getBilling(1l);
}
}
#Mapper(componentModel="spring")
public interface BillingMapper{
...
}
When I debug and I'm stuck in getBilling method in BillingService Class, billingMapper is alway null;
You are using very strange configuration. First of all you have method returning BillingService that doesn't specify any return value so this would not even compile. I suggest following way:
#Service
public BillingService{
private final BillingRepository billingRepository;
private final BillingMapper billingMapper;
// constructor with bean injection
public BillingService(final BillingRepository billingRepository,
final BillingMapper billingMapper) {
this.billingRepository = billingRepository;
this.billingMapper = billingMapper;
}
public void getBilling(Long billingId){
....
billingMapper.convertTo(...);
}
}
Then you can configure your test like following:
#RunWith(SpringJUnit4ClassRunner.class)
public class BillingServiceTest {
#Spy private BillingMapper billingMapper = Mappers.getMapper(BillingMapper.class);
#MockBean private BillingRepository billingRepository;
#Autowired private BillingService billingService;
#TestConfiguration
static class BillingServiceTestContextConfiguration {
#Bean public BillingService billingService() {
return new BillingService(billingRepository, billingMapper);
}
}
#Test
public void testGetBilling(){
List<Billing> billings = new ArrayList<>();
...
List<BillingPayload> payloads = new ArrayList<>();
when(billingRepository.findById(1L)).thenReturn(); // someResult
when(billingMapper.convertTo(billings)).thenReturn(payloads);
bilingService.getBilling(1l);
}
}
#Mapper(componentModel="spring")
public interface BillingMapper{
...
}
Similiar configuration should work. Main problem is that you are mixing #Autowired with setter/constructor injection (don't know since your weird method inside BillingService. Also dont know why you use #Spy annotation when you are tryning to Mock interface. #Spy is used to mock actual instance, while #Mock is mocking Class type. I would stick with #MockBean private BillingMapper billingMapper instead if BillingMapper is specified as Bean in your application.
Trying to get JUnit with mockito testing to work and getting a NPE on my test here. I'm wanting to have a verify that when createRegistrant(registrationDTO) is called, saveUpdateRegistration(Registration reg) method is called right after. An issue I find strange is that on Mockito.verify(registrationServiceImpl, Mockito.times(1)).createRegistrant(registrationDTO); it is not suggesting I can test if saveUpdateRegistration(Registration reg) method was called? IntelliJ only suggests methods that are in my interface?
My test code below:
#RunWith(MockitoJUnitRunner.class)
public class RegistrationServiceImplTest {
#InjectMocks
private RegistrationServiceImpl registrationServiceImpl;
#Mock
private RegistrationDTO registrationDTO;
#Mock
private Registration registration;
#Before
public void setup() {
registrationDTO.seteId("abc123");
registrationDTO.setTech("AWS");
registrationDTO.setFirstName("Bob");
registrationDTO.setLastName("Tom");
}
#Test
public void createRegistrant() throws Exception {
// Mockito.when(registrationServiceImpl.createRegistrant(registrationDTO)).thenReturn(registrationDTO);
Mockito.when(registrationServiceImpl.createRegistrant(registrationDTO)).thenReturn(registrationDTO);
registrationServiceImpl.createRegistrant(registrationDTO);
Mockito.verify(registrationServiceImpl, Mockito.times(1)).createRegistrant(registrationDTO);
}
Here is the code I'm testing:
package com.TechODex.service;
import com.TechODex.dto.RegistrationDTO;
import com.TechODex.model.Registration;
import com.TechODex.dao.RegistrationDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#Transactional
public class RegistrationServiceImpl implements RegistrationService {
#Autowired
private RegistrationDAO registrationDAO;
public RegistrationDTO createRegistrant(RegistrationDTO reg) {
saveUpdateRegistration(setDTOToModel(reg));
return reg;
}
public void deleteRegistrant(Long id) { deleteUserRegistrant(id); }
public List<Registration> findAllRegistrant(String tech) { return findAllRegistrantDAO(tech);}
public List<Registration> findAllTech() { return findAllTechDAO();}
private Registration setDTOToModel(RegistrationDTO dto){
Registration registration = new Registration();
registration.setFirstName(dto.getFirstName());
registration.setLastName(dto.getLastName());
registration.seteId(dto.geteId());
registration.setTech(dto.getTech());
return registration;
}
private void saveUpdateRegistration(Registration reg){ registrationDAO.save(reg);}
}
There are several issues here.
First, you do not mock RegistrationDAO. This will lead to it being null in the class under test. Next, RegistrationService is not a mock, yet you try to use when and verifyon it. Last, RegistrationDTO is mocked, so the invocations to the setters in #Before has no effect.
Your test should look something like:
#RunWith(MockitoJUnitRunner.class)
public class RegistrationServiceImplTest {
#InjectMocks
private RegistrationServiceImpl registrationServiceImpl;
#Mock
private RegistrationDAO registrationDAO;
private RegistrationDTO registrationDTO;
private Registration registration;
#Before
public void setup() {
registration = new Registration();
registration.seteId("abc123");
registration.setTech("AWS");
registration.setFirstName("Bob");
registration.setLastName("Tom");
registrationDTO = new RegistrationDTO();
registrationDTO.seteId("abc123");
registrationDTO.setTech("AWS");
registrationDTO.setFirstName("Bob");
registrationDTO.setLastName("Tom");
}
#Test
public void createRegistrant() throws Exception {
final RegistrationDTO result = registrationServiceImpl.createRegistrant(registrationDTO);
assertSame(registrationDTO, result);
verify(registrationDAO).save(eq(registration));
}
}
given that Registration has an implemented equals-method where the fields that are set are compared. If not, you need to use an ArgumentCaptor.
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;