How to write Junit test class for code coverage - java

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

How to write JUnit test case for void method

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

How to write junit for guice injected static variable which is declared inside Enum

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)
}

First mock of the method applied always

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);

Why doesn't my #Transactional method rollback when testing?

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)

How can I test a validator in a Spring Boot app?

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");

Categories

Resources