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
Related
I want to write a unit test for the following class;
I have started to implement the test and decided to mock "methodNotReadOnly" method first
but end up with null
routeQueryAdvisor object
and it does not matter. for using #Autowired or #InjectMock annotation?
How could I improve this?
Thanks.
RouteQueryAdvisor.class
#Aspect
#Component
#Order(0)
public class RouteQueryAdvisor {
private static final Log log = LogFactory.getLog(RouteQueryAdvisor.class);
private final DbHolder dbHolder;
public RouteQueryAdvisor(DbHolder dbHolder) {
this.dbHolder = dbHolder;
}
#Pointcut(value = "execution(* org.service.domain.rest.service.public_api.impl.*.*(..))")
public void aroundQueryPointCut() {
// Limit the observed transactions for db routing
}
#Around("aroundQueryPointCut()")
public Object proceed(ProceedingJoinPoint pjp) throws Throwable {
try {
if (methodNotReadOnly(pjp)) {
log.info("Proceeding on primary db - write for method " + pjp.getSignature().getName());
return pjp.proceed();
}
log.info("Proceeding on read db " + pjp.getSignature().getName());
Object res = pjp.proceed();
dbHolder.clearDbType();
return res;
} finally {
// clears the db context for next transaction
dbHolder.clearDbType();
}
}
private boolean methodNotReadOnly(#NotNull ProceedingJoinPoint pjp) {
return Arrays.stream(pjp.getTarget().getClass().getDeclaredMethods())
.filter(m -> m.isAnnotationPresent(RouteReadOnlyDB.class))
.filter(n -> n.getName().equals(pjp.getSignature().getName())).findAny().isEmpty();
}
}
Test class:
#PrepareOnlyThisForTest({Method.class})
public class RouteAspectTestMockedMethod {
#Autowired
private RouteQueryAdvisor routeQueryAdvisor;
#Mock
private ProceedingJoinPoint joinPoint;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testIdParamNotFound() throws Throwable {
Mockito.doReturn(routeQueryAdvisor.methodNotReadOnly(joinPoint)).doReturn(true);
Object o = routeQueryAdvisor.proceed(joinPoint);
}
}
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
}
I need to test if a lambda function is called n-times from a service instance.
I have a Service class, that interact with the repository, when an error occur on retriving data from repository the service should retry until a max number of retries is reached so I have implemented as follow:
interface Repository {
Collection<String> getData();
}
public class RetryHelper<T> {
private Integer retries;
public RetryHelper(Integer retries) {
this.retries = retries;
}
public interface Operation<T> {
T doIt() throws Exception;
}
public T doWithRetry(Operation<T> operation) throws Exception {
int remainRetries = retries;
do {
try {
return operation.doIt();
} catch (Exception e) {
if (remainRetries == 0) {
throw e;
}
//TODO: wait before retry
remainRetries--;
}
} while (true);
}
}
class Service {
#Inject
Repository repo;
private final RetryHelper<Collection<String>> retryHelper;
public Collection<String> callService() {
try {
Collection<String> res = retryHelper.doWithRetry(() ->
repo.getData());
return res;
} catch (Exception e) {
throw (CustomException) e;
}
}
}
I need to test using Mockito that repo.getData() is called n-times when error occurs. I can change the Service code and the RetryHelper, so I am open to suggestions.
I have try to implment the test following tutorials and documentations:
public class ServiceTest {
#Inject
Service service;
#InjectMock
Repository repository;
#InjectMock
RetryHelper<Collection<String>> retryHelper;
#Captor
ArgumentCaptor<RetryHelper.Operation<Collection<String>>> operation;
#BeforeEach
void init_mocks() {
MockitoAnnotations.openMocks(this);
}
#Test
void shouldRetryIfDataQueryFailsForNonFatalError() throws Exception {
when(repository.getData())
.thenThrow(new RuntimeException("Runtime Exception"));
service.callService();
verify(retryHelper).doWithRetry(operation.capture());
verify(repository, times(2)).getData();
}
}
The test fail with message that getData() is never called.
I have finally found the solution without using Captor
public class ServiceTest {
#Inject
Service service;
#InjectMock
Repository repository;
#Inject
RetryHelper<Collection<String>> retryHelper;
#Test
void shouldRetryIfDataQueryFailsForNonFatalError() throws Exception {
when(repository.getData())
.thenThrow(new RuntimeException("Runtime Exception"));
try {
service.callService();
} catch(Exception e) {
verify(repository, times(2)).getData();
}
}
}
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 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)