Can someone help me writing JUnit for the below serviceImpl class
#Component
public class ProcessStatusMasterServiceImpl implements ProcessStatusMasterService {
#Autowired
private ProcessStatusRepository processStatusRepository;
#Autowired
private ApplicationContext applicationContext;
public ProcessAndMacroStatus findProcessMaster(StatusConstant statusConstants) {
ProcessStatusMasterService thisBean = (ProcessStatusMasterService)this.applicationContext.getBean(ProcessStatusMasterService.class);
List<ProcessAndMacroStatus> processStatuses = thisBean.findProcessMasterByCategory(statusConstants.getCategory());
Optional<ProcessAndMacroStatus> processStatusOpt = processStatuses.stream().filter(f -> f.getProcessAndMacroStatusKey().equals(statusConstants.getKey())).findFirst();
if (processStatusOpt.isPresent())
return processStatusOpt.get();
throw new IllegalArgumentException("Unable to find status: " + statusConstants.getKey() + " for category: " + statusConstants.getCategory());
}
#Cacheable({"ProcessStatusMasterCache"})
public List<ProcessAndMacroStatus> findProcessMasterByCategory(String category) {
List<ProcessAndMacroStatus> processStatuses = this.processStatusRepository.findByProcessMacroStatusCategory(category);
return processStatuses;
}
}
below is the code i am trying, but i am getting NPE for line when(thisBean.findProcessMasterByCategory(StatusConstant.GROUP_STATUS_SUCCESS.getCategory())).thenReturn(processStatuses);
Reason for this variable thisbean is null
#RunWith(MockitoJUnitRunner.class)
public class ProcessStatusMasterServiceImplTest {
#Mock
ProcessStatusRepository processStatusRepository;
#Mock
ApplicationContext applicationContext;
#InjectMocks
ProcessStatusMasterServiceImpl processStatusMasterServiceImpl;
#Test
public void findProcessMaster() throws Exception {
ProcessStatusMasterService thisBean = (ProcessStatusMasterService)this.applicationContext.getBean(ProcessStatusMasterService.class);
List<ProcessAndMacroStatus> processStatuses=new ArrayList<ProcessAndMacroStatus>();
when(thisBean.findProcessMasterByCategory(StatusConstant.GROUP_STATUS_SUCCESS.getCategory())).thenReturn(processStatuses);
processStatusMasterServiceImpl.findProcessMaster(StatusConstant.GROUP_STATUS_SUCCESS);
}
}
I think you're trying to mock the behaviour of the tested entity itself instead of the mocked dependencies. I'd try mocking it like this:
#Test
public void findProcessMaster() throws Exception {
List<ProcessAndMacroStatus> processStatuses=new ArrayList<ProcessAndMacroStatus>();
when(processStatusRepository.findProcessMasterByCategory(StatusConstant.GROUP_STATUS_SUCCESS.getCategory())).thenReturn(processStatuses);
processStatusMasterServiceImpl.findProcessMaster(StatusConstant.GROUP_STATUS_SUCCESS);
}
Please remove your thisBean in your production code, just use this. instead.
List<ProcessAndMacroStatus> processStatuses = this.findProcessMasterByCategory(statusConstants.getCategory());
and modify your test
#Test
public void findProcessMaster() throws Exception {
List<ProcessAndMacroStatus> processStatuses = new ArrayList<ProcessAndMacroStatus> ();
when(processStatusRepository.findProcessMasterByCategory(StatusConstant.GROUP_STATUS_SUCCESS.getCategory())).thenReturn(processStatuses);
processStatusMasterServiceImpl.findProcessMaster(StatusConstant.GROUP_STATUS_SUCCESS);
// your assert
}
Related
I am trying to write Junit test cases for a void method. This method is used for updating values in Database. I have tried certain test cases and its returning a success. But when I check the coverage its showing zero. Can anyone tell me the proper way to write test cases for void methods.
this is my service class :
public class CustomerServiceImpl implements CustomerService {
#Autowired
ERepository eRepository;
#Autowired
ActivityUtil activityUtil;
#Override
public void updateCustomer(RequestDTO requestDTO)
throws CustomAException {
if (Objects.nonNull(requestDTO.getAdmissionId())) {
Optional<Admission> optionalAdmission = eRepository.findById(
requestDTO.getAdmissionId());
if (optionalAdmission .isPresent()) {
EAdmission eAdmission = optionalAdmission.get();
updateCustomer(requestDTO, eAdmission);
} else {
throw new CustomAException ("Admission details not found");
}
}
else {
throw new CustomAException ("Admission id not found");
}
}
private void updateCustomer(RequestDTO requestDTO,
EAdmission eAdmission)
throws CustomAException {
logger.info("updating customer info");
try {
if (ObjectUtils.isNotEmpty(eAdmission.getCustomer())) {
eAdmission.getCustomer().setCustomerEmailAddress(
requestDTO.getEmail());
eAdmission.getCustomer().setCorporateTelephoneNumber(
requestDTO.getCustomerPhone());
eAdmission.getCustomer().setZipCode(requestDTO.getZipCode());
eAdmission.getCustomer().setCustomerAddress1(requestDTO.getAddress1());
evfAdmissionRepository.save(evfAdmission);
activityUtil.createActivityLog(eAdmission, Constants.ENTRY_COMPLETED);
} else {
throw new CustomAException ("Customer details not found ");
}
} catch (Exception exception) {
logger.error(Constants.CUSTOMER_UPDATE_ERROR_MESSAGE);
throw new CustomAException (Constants.CUSTOMER_UPDATE_ERROR_MESSAGE);
}
I am trying to write test cases for updateCustomer but my test class has zero coverage even though its a success.
test class :
#SpringBootTest
public class CustomerServiceImplTest {
#InjectMocks
CustomerServiceImpl CustomerServiceImpl;
#Mock
ERepository eRepository ;
#Mock
ActivityUtil activityUtil;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCustomerException() throws Exception {
CustomerServiceImpl CustomerServiceImplTest = mock(CustomerServiceImpl.class);
when(evfAdmissionRepository.findById(any())).thenThrow(ConstraintViolationException.class);
Mockito.doThrow(CustomAException .class).when(CustomerServiceImplTest).updateCustomer(setRequestDTO());
}
#Test
public void updateCustomerSuccess() throws Exception {
CustomerServiceImpl CustomerServiceImplTest = mock(CustomerServiceImpl.class);
CustomerServiceImplTest .updateCustomer(setRequestDTO());
//doNothing().when(evfCustomerServiceImpl).updateEVFCustomerOnSubscribe(any());
verify(CustomerServiceImplTest ).updateCustomerOn(setRequestDTO());
}
private RequestDTO setRequestDTO() {
RequestDTO eRequestDTO = new RequestDTO ();
eRequestDTO .setEmail("test");
// rest of code for setting value
return eRequestDTO ;
}
ArgumentCaptor can be used to capture and Assert Arguments in your method. you can read about ArgumentCaptor here
I have enum like this
public enum NumbersJk {
ONE {
public void processCommand(Info Info) {
log.info("what is in process " + process)
process.add(Info);
}
},
TWO {
public void processCommand(Info Info) {
process.subtract(Info);
}
},
TEN {
public void processCommand(Info Info) {
process.divide(Info);
}
}
#Inject
private static ProcessNumber process;
public abstract void processCommand(Info Info) throws Exception;
}
It was injected using guice like this requestStaticInjection(NumbersJk.class);
public class AddNumbers {
public string testMethod(bla,bla,commandToExecute){
Info info = convert(bla,bla)
NumbersJk.valueOf(commandToExecute).processCommand(Info);
}
}
Now I am trying to write junit (powermockito) for this
Junit
#Mock
private ProcessNumber process = new ProcessNumber(new depsencey(), dependecny2());
#InjectMocks
AddNumber addNumber;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
#SneakyThrows
public void test() {
addNumber.testMethod(1,2,ONE)
}
This internally calls
NumbersJk.valueOf(commandToExecute).processCommand(Info);
And getting exception java.lang.NullPointerException: null
This is ProcessNumber is coming as null
log.info("what is in process " + process) printed as `what is in process null`
Question:
How to inject the class ProcessNumber in junit
Thanks
Jk
I figured it out.
We can use powermock to solve this problem Whitebox.setInternalState(NumbersJk.class, process);
Code:
#Mock
private ProcessNumber process = new ProcessNumber(new depsencey(), dependecny2());
#InjectMocks
AddNumber addNumber;
#Before
public void setUp() throws Exception {
Whitebox.setInternalState(NumbersJk.class, process);
MockitoAnnotations.initMocks(this);
}
#Test
#SneakyThrows
public void test() {
addNumber.testMethod(1,2,ONE)
}
I want to test a few cases in a method by mocking external dependency to return different results for every test case. But when always returns what is defined at first time (in this example - empty set) and that brokes the next tests.
If I run tests one by one they pass successfully but when I run the whole class only the first test pass and others fail.
Testing class:
class ExampleTest {
#Mock
private Dao dao;
#Mock
private Validator validator;
#Spy
#InjectMocks
Controller controller;
#BeforeEach
void setUp() {
initMocks(this);
}
private final static Set DATA = Set.of("data1", "data2");
#Test
void firstTest() throws UserDashboardException, DashboardException, WidgetException {
when(validator.filter(DATA)).thenReturn(Collections.emptySet());
assertThrows(Exception.class, () -> controller.create(DATA));
}
#Test
void secondTest() throws UserDashboardException, DashboardException, WidgetException {
when(validator.filter(DATA)).thenReturn(DATA);
controller.create(DATA);
verify(dao, times(1)).create(eq(DATA));
}
}
Tested class:
public class Controller {
private Dao dao;
private Validator validator;
public Controller(Dao dao,Validator validator) {
this.dao = dao;
this.validator = validator;
}
public String create(Set<String> data) {
data = validator.filter(data);
if (data.isEmpty()) {
throw new Exception("Invalid data.");
}
return dao.create(data);
}
}
So, in both tests create method throws an exception which is not what I expect. Maybe I miss some point?
Have you tried with doReturn method?
doReturn(DATA).when(validator).filter(DATA)
which can be import from org.mockito.Mockito.doReturn;
Edited: there might be a bug inside your code implementation:
data = validator.filter(data);
I have #transactional method that seems to be working (rolling back) if run the actual service and provide inputs that would cause a run-time error. If I create a Test for that method that throws a run-time error it doesn't seem to rollback anymore. Any idea why this doesn't work while testing?
it's somthing like:
#Service
public class SampleServiceImpl implements SampleService {
private final RepoA repoA;
private final RepoB repoB;
public SampleServiceImpl(RepoA repoA, RepoB repoB) {
this.repoA = repoA,
this.repoB = repoB
}
#Transactional
#Override
public void addItems() {
repoA.save(new ItemA(1,'name1')); //works
repoB.save(new ItemB(2,'name2')); //throws run-time error
}
}
#RunWith(SpringRunner.class)
#DataJpaTest
public class Tests {
#Autowired
private RepoA repoA;
#Mock
private Repob repoBMock;
#Test
public void whenExceptionOccurrs_thenRollsBack() {
var service = new SampleService(repoA, repoBMock);
Mockito.when(repoBMock.save(any(ItemB.class))).thenThrow(new RuntimeException());
boolean exceptionThrown = false;
try {
service.addItems()
} catch (Exception e) {
exceptionThrown = true;
}
Assert.assertTrue(exceptionThrown);
Assert.assertFalse(repoA.existsByName('name1')); // this assertion fails because the the first item still exists in db
}
}
Just add annotation Rollback and set the flag to false.
#Test
#Rollback(false)
I have a class:
#Component
public class ContractorFormValidator implements Validator {
Logger logger = LoggerFactory.getLogger(ContractorFormValidator.class);
#Inject IBusinessDataValidator businessDataValidator;
#Override
public boolean supports(Class<?> clazz) {
return Contractor.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
Contractor contractor = (Contractor) target;
if (!businessDataValidator.isNipValid(contractor.getContractorData().getNip())) {
errors.rejectValue("contractorData.nip", "invalid");
}
if (!businessDataValidator.isRegonValid(contractor.getContractorData().getRegon())) {
errors.rejectValue("contractorData.regon", "invalid");
}
}
}
How can I test it? I have tried this: How to test validation annotations of a class using JUnit? but this doesn't work cause the validate method in my validator requires Errors class passed to it's method signature.
I have no Idea if I can pass this Errors object to the validator. Is there any other way?
Have you tried to write a simple unit test for this?
#RunWith(SpringJUnit4ClassRunner.class)
public class ContractorFormValidatorTest {
#Autowired
private ContractorFormValidator validator;
#Test
public void testValidation() throws Exception {
Contractor contractor = new Contractor();
// Initialise the variables here.
Errors errors = new BeanPropertyBindingResult(contractor, "contractor");
validator.validate(contract, errors);
// If errors are expected.
Assert.assertTrue(errors.hasErrors());
for (Error fieldError : errors.getFieldErrors()) {
Assert.assertEquals("contractorData.nip", fieldError.getCode());
}
}
}
If you are going to use the validator in a controller implementation, then you need to use the MockMvc apis
Your set up can be included in the class above.
private MockMvc mockMvc
#Autowired
private MyController controller;
#Before
public void setUp() throws Exception {
this.mockMvc = MockMvcBuilders.standaloneSetup(this.controller).build();
}
#Test
public void testMethod() {
MvcResult result = this.mockMvc.perform(MockMvcRequestBuilders.post("/yoururl")).
andExpect(MockMvcResultMatchers.status().isCreated()).andReturn();
}
Use the class org.springframework.validation.BeanPropertyBindingResult,
Errors newErrors = new BeanPropertyBindingResult(validateObject, "objectName");