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 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);
}
}
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)
}
public class ProjectIdInitializer {
public static void setProjectId(String projectId) {
//load spring context which i want to escape in my test
}
}
public class MyService {
public Response create(){
...
ProjectIdInitializer.setProjectId("Test");
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({ProjectIdInitializer.class})
public class MyServiceTest{
#InjectMocks
private MyService myServiceMock ;
public void testCreate() {
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
// Does not work,still tries to load spring context
Response response=myServiceMock .create();
}
How can i make sure that nothing happens if ProjectIdInitializer.setProjectId() is called from myservice?
As stated in comments, you should be aware that many things might break because of PowerMock.
You need to use PowerMock runner, something like that:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ProjectIdInitializer.class)
public class MyServiceTest{
private MyService myService = new MyService();
public void testCreate()
{
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
Response response=myService.create();
}
}
see also this doc.
This self contained sample:
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.ProjectIdInitializer.class)
public class A {
private MyService myService = new MyService();
#Test
public void testCreate() throws Exception {
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
System.out.println("Before");
Response response = myService.create();
System.out.println("After");
}
public static class ProjectIdInitializer {
public static void setProjectId(String projectId) {
//load spring context which i want to escape in my test
System.out.println(">>>>>> Game over");
}
}
public static class Response {
}
public static class MyService {
public Response create() {
// ...
ProjectIdInitializer.setProjectId("Test");
return null;
}
}
}
outputs:
Before
After
As expected
Is there a way to get a class that extends AbstractTransactionalJUnit4SpringContexts to play nicely with JUnit's own #RunWith(Parameterized.class), so that fields marked as Autowired get wired in properly?
#RunWith(Parameterized.class)
public class Foo extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired private Bar bar
#Parameters public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Test public void someTest(){
bar.baz() //NullPointerException
}
}
See http://jira.springframework.org/browse/SPR-5292
There is a solution.
You can use a TestContextManager from Spring. In this example, I'm using Theories instead of Parameterized.
#RunWith(Theories.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class SeleniumCase {
#DataPoints
public static WebDriver[] drivers() {
return new WebDriver[] { firefoxDriver, internetExplorerDriver };
}
private TestContextManager testContextManager;
#Autowired
SomethingDao dao;
private static FirefoxDriver firefoxDriver = new FirefoxDriver();
private static InternetExplorerDriver internetExplorerDriver = new InternetExplorerDriver();
#AfterClass
public static void tearDown() {
firefoxDriver.close();
internetExplorerDriver.close();
}
#Before
public void setUpStringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Theory
public void testWork(WebDriver driver) {
assertNotNull(driver);
assertNotNull(dao);
}
}
I found this solution here : How to do Parameterized/Theories tests with Spring
You can use SpringClassRule and SpringMethodRule for this purpose
#RunWith(Parameterized.class)
#ContextConfiguration(...)
public class FooTest {
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private Bar bar
#Parameters
public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Test
public void someTest() {
bar.baz() //NullPointerException
}
}
No, you can't. The superclass has:
#RunWith(SpringJUnit4ClassRunner.class)
which assures that the tests are run within spring context. If you replace it, you are losing this.
What comes to my mind as an alternative is to extend SpringJunit4ClassRunner, provide your custom functionality there and use it with #RunWith(..). Thus you will have the spring context + your additional functionality. It will call super.createTest(..) and then perform additional stuff on the test.
I've had to handle the transactions programmatically (see http://www.javathinking.com/2011/09/junit-parameterized-test-with-spring-autowiring-and-transactions/):
#RunWith(Parameterized.class)
#ContextConfiguration(locations = "classpath*:/testContext.xml")
public class MyTest {
#Autowired
PlatformTransactionManager transactionManager;
private TestContextManager testContextManager;
public MyTest (... parameters for test) {
// store parameters in instance variables
}
#Before
public void setUpSpringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Parameterized.Parameters
public static Collection<Object[]> generateData() throws Exception {
ArrayList list = new ArrayList();
// add data for each test here
return list;
}
#Test
public void validDataShouldLoadFully() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
status.setRollbackOnly();
try {
... do cool stuff here
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
});
}
Here's how I made it work in Spring Boot 1.5.7:
Add the #RunWith(Parameterized.class) annotation to your class
Inject your dependency as class field with:
#Autowired
private Bar bar;
Add your parameter/s as class fields:
private final int qux;
private final Boolean corge;
private final String grault;
Add a constructor to initialize the parameter/s as follows:
public Foo(int qux, Boolean corge, String grault) throws Exception {
this.qux = qux;
this.corge = corge;
this.grault = grault;
new TestContextManager(getClass()).prepareTestInstance(this);
}
Add a static method data that returns a Collection containing the values of your parameters at each iteration, respecting the order by which they are passed to the constructor:
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ 1, Boolean.FALSE, "Hello" },
{ 2, Boolean.TRUE, null },
{ 3, null, "world" }
});
}
Write your test using the class fields declared above like follows:
#Test public void someTest(){
// Some arrangements
// Some actions
assertThat(myTestedIntValue, is(equalTo(qux));
assertThat(myTestedBooleanValue, is(equalTo(corge));
assertThat(myTestedStringValue, is(equalTo(grault));
}
Inspired by Simon's solution, you can use TestContextManager also with Parameterized runner:
#RunWith(Parameterized.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class MyTestClass {
#Parameters public static Collection data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Before
public void setUp() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
}
}
Here is full example
I am not sure about handling #Transactional in this case.