Powermock error mock object injected using spring when mocking static object - java

I am using PowerMock easy mock to mock static method of a class. I have two test cases written, which if I run independently run fine, but give me an error while running simultaneously.
CarTest:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ServiceCaller.class })
public class CarTest {
ServiceCaller mockServiceCallerObjectToReturn;
public CarTest() {
PowerMock.mockStaticPartial(ServiceCaller.class, "getInstance");
mockServiceCallerObjectToReturn = PowerMock.createMock(ServiceCaller.class);
EasyMock.expect(ServiceCaller.getInstance()).andReturn(mockServiceCallerObjectToReturn);
}
#Test
public void test1() throws IOException {
PowerMock.reset(mockServiceCallerObjectToReturn);
PowerMock.reset(ServiceCaller.class);
EasyMock.expect(ServiceCaller.getInstance()).andReturn(mockServiceCallerObjectToReturn);
EasyMock.expect(mockServiceCallerObjectToReturn.checkValidity("testDriver")).andReturn(false);
PowerMock.replay(mockServiceCallerObjectToReturn);
PowerMock.replay(ServiceCaller.class);
Car car = CarFactory.getInstance().getCar();
boolean canDrive = car.drive("testDriver");
Assert.assertEquals(canDrive, false);
PowerMock.verify(mockServiceCallerObjectToReturn);
PowerMock.verify(ServiceCaller.class);
}
#Test
public void test2() throws IOException {
PowerMock.reset(mockServiceCallerObjectToReturn);
PowerMock.reset(ServiceCaller.class);
EasyMock.expect(ServiceCaller.getInstance()).andReturn(mockServiceCallerObjectToReturn);
EasyMock.expect(mockServiceCallerObjectToReturn.checkValidity("testDriver")).andReturn(false);
PowerMock.replay(mockServiceCallerObjectToReturn);
PowerMock.replay(ServiceCaller.class);
Car car = CarFactory.getInstance().getCar();
boolean canDrive = car.drive("testDriver");
Assert.assertEquals(canDrive, false);
PowerMock.verify(mockServiceCallerObjectToReturn);
PowerMock.verify(ServiceCaller.class);
}
}
CarFactory:
public class CarFactory {
private static final String CAR_SPRING_CONTEXT_XML = "/com/archit/mock/spring-config/CarSpringContext.xml";
protected static final ApplicationContext CONTEXT = new ClassPathXmlApplicationContext(new String[] { CAR_SPRING_CONTEXT_XML });
private static final CarFactory INSTANCE = new CarFactory();
public static CarFactory getInstance() {
return INSTANCE;
}
public Car getCar() {
return CONTEXT.getBean("car", Car.class);
}
}
Car:
package com.archit.mock;
public class Car {
private final ServiceCaller serviceCaller;
public Car(final ServiceCallerFactory serviceCallerFactory) {
this.serviceCaller = serviceCallerFactory.getServiceCaller();
}
public boolean drive(final String driver) {
return (serviceCaller.checkValidity(driver));
}
}
ServiceCaller:
package com.archit.mock;
public class ServiceCaller {
private static class ServiceCallerHolder {
private static ServiceCaller INSTANCE = new ServiceCaller();
}
public static ServiceCaller getInstance() {
return ServiceCallerHolder.INSTANCE;
}
public boolean checkValidity(final String x) {
// Do some call
throw new IllegalStateException("This should have been mocked");
}
}
ServiceCallerFactory:
package com.archit.mock;
public class ServiceCallerFactory {
public ServiceCaller getServiceCaller() {
return ServiceCaller.getInstance();
}
}
Spring Config:
<bean name="car" class="com.archit.mock.Car">
<constructor-arg>
<ref bean="serviceCallerFactory" />
</constructor-arg>
</bean>
<bean name="serviceCallerFactory" class="com.archit.mock.ServiceCallerFactory" />
Error:
java.lang.AssertionError:
Unexpected method call ServiceCaller.checkValidity("testDriver"):
ServiceCaller.checkValidity("testDriver"): expected: 1, actual: 2
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:85)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:94)
at com.archit.mock.ServiceCaller$$EnhancerByCGLIB$$9848ad9e.checkValidity(<generated>)
at com.archit.mock.Car.drive(Car.java:12)
at com.archit.mock.CarTest.test2(CarTest.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:42)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Other Observations:
Making the object scope as prototype in spring config works fine.
Both tests when run individually work fine.
Based on above 2, It seems to be a problem with re-setting the mocks.

I've found it easier with mocks to have them start as new objects each time the tests are run. You can achieve this by having all your mock objects at the top as private variables, using the Mockito.Mock annotation:
#Mock
private MockOneClass mockOne;
...
#Mock
private MockNClass mockN;
Then using the JUnit Before annotation, create a setup function of some sort that initializes all the mock objects:
#Before
public void setup() {
// initialize all the #Mock objects
MockitoAnnotations.initMocks(this);
}
This way, before each test runs you get a new Mock created, which you can then apply any amount of expects and functionality to, without having to worry about clearing out any old mocking done in a previous test. If you have any Mock that you know will provide some specific functionality (static singleton mock getInstance calls for example) can be called in this setup function to help keep the tests cleaner of Mock resetting.
I have some test that has 10+ tests all run in a row that uses this framework. Not only does it make it a lot easier to read, but it makes setting up tests from scratch really fast. Being able to copy old mock setups in Tests and remove/change certain pieces is so much easier then having to upkeep every mock object every test, which just doesn't extend well once you start getting more tests.

Related

Injecting beans in a JUnit/Mockito test returns zero

I have a JavaEE application with Stateless EJBs that I use for business logic (EjbBusiness) and database access (EjbDAO). I need to run a unit test on EjbBusiness, but the DAO method always returns zero.
In the example below I have both classes and the unit test. I mock the EjbDAO method that connects to the database, to return a testing SQL connection:
#Stateless
public class EjbDAO {
public Connection getConnFromPool() {
Connection conn = null; // in production this would return a connection
return conn;
}
public int add2(int i) {
Connection conn = getConnFromPool();
System.out.println("in EjbDAO: " + i);
return i + 2;
}
}
#Stateless
public class EjbBusiness {
#Inject
private EjbDAO dao;
public int add2(int i) {
int j = dao.add2(i);
System.out.println("in EjbBusiness: " + j);
return j;
}
}
Since I mock one of the methods of EjbDAO, I annotate it with #Spy in UnitTest:
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
#InjectMocks
private EjbBusiness biz;
#InjectMocks
#Spy
private EjbDAO dao;
#Before
public void setup() {
dao = Mockito.mock(EjbDAO.class);
biz = Mockito.mock(EjbBusiness.class);
MockitoAnnotations.initMocks(this);
}
#Test
public void testBean() {
// this would return the testing connection
Mockito.doReturn(null).when(dao).getConnFromPool();
int i = biz.add2(3);
assertThat(5).isEqualTo(i);
}
}
Problem is that the assertion doesn't work, as biz.add2(3) returns zero instead of 5. Also, the System.out.println in both beans is not printed. How to declare/mock the beans for the test to work?
Use #InjectMocks only when you calling actual method otherwise don't use it. And also don't use #InjectMocks and Mockito.mock() or #Mock together.
In your code you are using #InjectMocks on dao object and you are also creatign mock for that. And use Mockito.mock() when you want to stub the method calls instead of calling actual methods.
System.out.println() is not working in your code because you created mocks for objects biz and dao. Actual methods (i.e add2() because of this you are getting 0 as output) not executed when you call with mock objects.
For more info on when to use #InjectMocks refer
this
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
#InjectMocks
private EjbBusiness biz;
#Mock
private EjbDAO dao;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testBean() {
// this would return the testing connection
Mockito.doReturn(null).when(dao).getConnFromPool();
Mockito.doCallRealMethod().when(dao).add2(Mockito.anyInt());
int i = biz.add2(3);
assertThat(i).isEqualTo(5);
}
}
You should not use one unit test to test both classes.
You should have two test classes to test them.
For Example,
#RunWith(MockitoJUnitRunner.class)
public class EjbBusinessTest {
#InjectMocks
private EjbBusiness biz;
#Mock
private EjbDAO dao;
#Test
public void testAdd2() {
// this would return the testing connection
Mockito.doReturn(null).when(dao).getConnFromPool();
Mockito.doReturn(5).when(dao).add2();
int i = biz.add2(3);
assertThat(5).isEqualTo(i);
}
}
In the above class we are testing only the method EjbBusinessTest.add2 and we don't care what happens or if the method EjbDAO.add2 is working properly. In this all we should care is whether the method under test is working properly, hence we mock everything external to that method.
Following a similar approach for EjbDAO.add2 as well, The test case should look like something given below. I have also made the method EjbDAO.getConnection private so that that should also be included in the test. This choice should be made by you if you need to make it private or public. If you decide to keep it public then you should use #Spy on EjbDAO and mock the EjbDAO.getConnection method.
#RunWith(MockitoJUnitRunner.class)
public class EjbDAOTest {
//instantiate this object the way you want. Mock the external objects used inside this like the library used to get connection inside EjbDAO.getConnection() Method
#InjectMocks
private EjbDAO dao;
#Test
public void testAdd2() {
// I would suggest you to make the getConnection method private.
// do not mock the getConnection here, instead mock how you are getting the connection inside the getConnection method.
int i = dao.add2(3);
assertThat(5).isEqualTo(i);
}
}
Hope it helps.

How to use EasyMock objects in JUnit #Before method as well as test method

I am attempting to use EasyMock alongside JUnit and have run into difficulties while scheduling method calls on a mocked dependency in a JUnit 4 #Before method.
In the below example the test class MockWithBeforeTest is testing the class ClassUnderTest. Dependency is passed to ClassUnderTest's constructor, in which one of Dependency's methods is called, returning a value needed to initialise ClassUnderTest. This process of initialising ClassUnderTest will be the same for all tests, so I decorate the ClassUnderTest#setUp method with a JUnit 4 #Before annotation.
When testing the method ClassUnderTest#getDerived we expect a call to the mocked Dependency instance to return a value, which we schedule in the method MockWithBeforeTest#testGetDerived. However, this test unexpectedly fails with the error Unexpected method call Dependency.getB() despite the fact that this call is scheduled in MockWithBeforeTest#testGetDerived.
How should I modify the example code such that MockWithBeforeTest#testGetDerived passes?
Example code
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import org.easymock.EasyMockRule;
import org.easymock.Mock;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
public class MockWithBeforeTest {
#Rule
public EasyMockRule rule = new EasyMockRule(this);
#Mock
private Dependency dependency;
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
expect(this.dependency.getA()).andReturn(2);
replay(this.dependency);
this.classUnderTest = new ClassUnderTest(this.dependency);
verify(this.dependency);
}
#Test
public void testGetDerived() {
expect(this.dependency.getB()).andReturn(3);
replay(this.dependency);
assertEquals(6, this.classUnderTest.getDerived(1));
verify(this.dependency);
}
}
class ClassUnderTest {
private int a;
private Dependency dependency;
ClassUnderTest(Dependency dependency) {
this.a = dependency.getA();
this.dependency = dependency;
}
void setA(int val) {
this.a = val;
}
int getDerived(int val) {
return val * this.a * this.dependency.getB();
}
}
class Dependency {
private int a;
private int b;
Dependency(int a, int b) {
this.a = a;
this.b = b;
}
int getA() {
return this.a;
}
int getB() {
return this.b;
}
}
Stack Trace
java.lang.AssertionError:
Unexpected method call Dependency.getB():
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:101)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
at Dependency$$EnhancerByCGLIB$$6d3a4341.getB(<generated>)
at MockWithBeforeTest.testGetDerived(MockWithBeforeTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.easymock.internal.EasyMockStatement.evaluate(EasyMockStatement.java:43)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Why not create an instance of Dependency to pass to the constructor?
The example given above is representative of a general problem in which the dependency passed to the class under test is much more complex than Dependency.
Speculation about design problem
I am mindful of the fact that details of the class under test's implementation are leaking into the test class via the scheduled methods on the mocked dependency. However I am not experienced enough with mocking frameworks to tell if this is an unavoidable side effect of mocking, or a symptom of a flaw in my design. Any guidance on this would be appreciated.
Software version information
Java: 1.8.0_201
JUnit: 4.12
EasyMock: 4.2
More research and discussion with colleagues produced a solution. The step I missed is to reset the mocked Dependency object using EasyMock.reset(this.dependency) to allow additional expected calls to be added in the test methods. The fixed MockWithBeforeTest is
public class MockWithBeforeTest {
#Rule
public EasyMockRule rule = new EasyMockRule(this);
#Mock
private Dependency dependency;
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
expect(this.dependency.getA()).andReturn(2);
replay(this.dependency);
this.classUnderTest = new ClassUnderTest(this.dependency);
verify(this.dependency);
reset(this.dependency); // Allow additional expected method calls to be specified
// in the test methods
}
#Test
public void testGetDerived() {
expect(this.dependency.getB()).andReturn(3);
replay(this.dependency);
assertEquals(6, this.classUnderTest.getDerived(1));
verify(this.dependency);
}
}
The replay() must be called only once, after everything is recorded. That's why it doesn't work here.
Since, in your case you are using the mock in the constructor, you need to instantiate the tested class after the replay.
public class MockWithBeforeTest {
#Rule
public EasyMockRule rule = new EasyMockRule(this);
#Mock
private Dependency dependency;
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
expect(this.dependency.getA()).andReturn(2);
}
#Test
public void testGetDerived() {
expect(this.dependency.getB()).andReturn(3);
replay(this.dependency);
this.classUnderTest = new ClassUnderTest(this.dependency);
assertEquals(6, this.classUnderTest.getDerived(1));
verify(this.dependency);
}
}
You could also reset the mock in between but I'm not sure I like that. It will let you pass the constructor and then reuse the mock for the actual test with a new recording.
public class MockWithBeforeTest {
#Rule
public EasyMockRule rule = new EasyMockRule(this);
#Mock
private Dependency dependency;
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
expect(this.dependency.getA()).andReturn(2);
replay(this.dependency);
this.classUnderTest = new ClassUnderTest(this.dependency);
reset(this.dependency);
}
#Test
public void testGetDerived() {
expect(this.dependency.getB()).andReturn(3);
replay(this.dependency);
assertEquals(6, this.classUnderTest.getDerived(1));
verify(this.dependency);
}
}

Injecting mock before Spring's post-construct phase

Basically, the question is in the title.
I faced a problem that in post-construct phase my bean (that is autowired in the bean that is going through post-construct phase right now) is already mocked, but all the behavior described by Mockito.when() doesn't work, all the calls return null.
While searching I found this solution.
But is it possible to make it work without using any 3rd party libraries?
Test class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#ContextConfiguration(classes = TestApplicationConfiguration.class)
public class ServiceTest {
#Autowired
#Qualifier("test")
private PCLPortType pclPortType;
#MockBean
private ClearingHelper сlearingHelper;
#MockBean
private OrganizationCacheRepository organizationCacheRepository;
#Before
public void setup() throws Exception{
OperationResultWithOrganizationSystemIdMappingList res = new OperationResultWithOrganizationSystemIdMappingList();
when(clearingHelper.getOrgIdSystemIdMapping(any(Keycloak.class))).thenReturn(res);
}
#Test
public void test() throws Exception{
pclPortType.call("123");
}
}
Test config:
#TestConfiguration
public class TestApplicationConfiguration {
#Bean(name = "test")
public PCLPortType pclPortTypeForTest() throws JAXBException {
...
}
#Bean
public Keycloak keycloak() {
return Mockito.mock(Keycloak.class);
}
}
Component where I want to get mocked beans:
#Component
public class OrganizationCacheJob {
private static final Logger logger =
LogManager.getLogger(OrganizationCacheJob.class);
private final ObjectFactory<Keycloak> factory;
private final ClearingHelper clearingHelper;
private final OrganizationCacheRepository organizationCacheRepository;
#Autowired
public OrganizationCacheJob(ObjectFactory<Keycloak> factory,
ClearingHelper clearingHelper,
OrganizationCacheRepository organizationCacheRepository) {
this.factory = factory;
this.clearingHelper = ClearingHelper;
this.organizationCacheRepository = organizationCacheRepository;
}
#PostConstruct
public void updateCacheRepository() {
doUpdateCacheRepository();
}
#Scheduled(cron = "${organization.cache.schedule}")
public void start() {
logger.info("Starting update organization cache.");
doUpdateCacheRepository();
logger.info("Job finished.");
}
private void doUpdateCacheRepository() {
try {
Keycloak keycloak = factory.getObject();
OperationResultWithOrganizationSystemIdMappingList orgIdSystemIdMapping = clearingHelper.getOrgIdSystemIdMapping(keycloak);
if (orgIdSystemIdMapping != null) {
orgIdSystemIdMapping.getContent().forEach(o -> organizationCacheRepository.saveOrgIdsSystemsIdsMappings(o.getOrgId(), o.getId()));
logger.debug("Was saved {} orgIds", orgIdSystemIdMapping.getContent().size());
}
} catch (Exception e) {
logger.error("Error fetching whole mapping for org and systems ids. Exception: {}", e);
}
}
}
So, in post-construct phase of OrganizationCacheJob I want to get res when calling clearingHelper, but instead I get null.
ClearingHelper is a regular Spring bean marked as a #Component with public methods.
Ahh ok I just realized - when you start your test case, whole env is up and running first, then you advance to testing phase. So, translating to your case - first you got injection and post-constructs called, then #Before method is done, thus the result.
So as you can see, code says more than all the words you could put in your original post.
If it is possible for you, use spies insteed of mocks. If it is not possible to construct that, you will have to redesign your tests to not rely on post construct.
In this case, since you want the same post-construct behavior for every test case, provide own factory method for given mock (like you did with keycloak) and move when-doReturn there. It will be guaranteed that it will happen before post construct.

Test class should have exactly one public zero-argument constructor

I have written a test class, such that is following
public class MyParameterizedClassTest extends BaseRepositoryTest {
private int multiplierA;
private int multiplierB;
public MyParameterizedClassTest(int multiplierA) {
this.multiplierA = multiplierA;
}
#Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { 1 }, { 5 }, { 121 } };
return Arrays.asList(data);
}
#Test
public void testMultiplyException() {
assertEquals("Result", multiplierA * multiplierA,multiply(multiplierA));
}
public int multiply(int a){
return a*a;
}
}
And My BaseRepositoryTest class is following
#RunWith (Parameterized.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public abstract class BaseRepositoryTest extends
AbstractJUnit4SpringContextTests {
#Inject
SessionFactory sessionFactory;
private Transaction transaction;
public Session getSession() {
Session session;
try {
session = sessionFactory.getCurrentSession();
} catch (SessionException se) {
session = sessionFactory.openSession();
}
return session;
}
#Before
public void setUp() throws Exception {
transaction = getSession().beginTransaction();
}
#After
public void tearDown() throws Exception {
if (transaction != null) {
transaction.rollback();
}
getSession().close();
}
#Before
public void baseSetUp() {
MockitoAnnotations.initMocks(this);
}
}
When I run my test class it shows like,
Test class should have exactly one public zero-argument constructor:at
org.junit.runners.BlockJUnit4ClassRunner.validateZeroArgConstructor
I want to make a test method with #parameters,so please Can anyone please help to find the solution
JUnit 4 vs 5 (Jupiter)
I had this issue when I imported the wrong Test class. While a constructor was using JUnit 5 features, I imported the old org.junit.Test rather than org.junit.jupiter.api.Test.
I think the problem is that you defined two test runners. One by yourself #RunWith (Parameterized. class) and one that comes with spring, because an AbstractJUnit4SpringContextTests defines a #RunWith(SpringJUnit4ClassRunner.class).
Since Junit can only deal with one #RunWith you can only use #Parameterized or AbstractJUnit4SpringContextTests. If you want to use both you have to use #Parameterized and than do the same logic that a SpringJUnit4ClassRunner does on your own.
A simple approach can be to just use spring's org.springframework.test.context.TestContextManager.
#RunWith(Parameterized.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public abstract class BaseRepositoryTest extends AbstractJUnit4SpringContextTests {
private TestContextManager testContextManager;
#Before
public void setUpContext() throws Exception {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
}
}
But this only ensures that the TestExecutionListeners are invoked. Spring normally does a lot more like application context caching and so on. Also a tear down method should be implemented that closes the application context.
If you're running a single test, make sure that you wrote your test class name correctly
A common mistake that I do is to have a class named 'Foo' and a test class named
'FooTest'
and run a single unit test with
'Foo'
instead of 'FooTest'
If 'Foo' has a public constructor with arguments I get the error:
java.lang.Exception: Test class should have exactly one public zero-argument constructor
This error is thrown when your class is not defined as public
In your case it is abstract, so it can not be instantiate for testing propouses
Try removing constructor from MyParameterizedClassTest class.
I was getting this error when my test class had a public constructor. After removing, it started working.
I have got one answer,it fix on my machine
JUnit4 -> when u check the exception
org.junit.runners.BlockJUnit4ClassRunner.validateZeroArgConstructor(BlockJUnit4ClassRunner.java:171)
org.junit.runners.BlockJUnit4ClassRunner.validateConstructor(BlockJUnit4ClassRunner.java:148)
get inside to first exception
protected void validateZeroArgConstructor(List<Throwable> errors) {
if(!this.getTestClass().isANonStaticInnerClass() && this.hasOneConstructor() && this.getTestClass().getOnlyConstructor().getParameterTypes().length != 0) {
String gripe = "Test class should have exactly one public zero-argument constructor";
errors.add(new Exception(gripe));
}
}
it will check your constructor is none-parameters or not
Try setter injection or field(->field is not recommended officially)

Junit - run set up method once

I set up a class with a couple of tests and rather than using #Before I would like to have a setup method that executes only once before all tests. Is that possible with Junit 4.8?
Although I agree with #assylias that using #BeforeClass is a classic solution it is not always convenient. The method annotated with #BeforeClass must be static. It is very inconvenient for some tests that need instance of test case. For example Spring based tests that use #Autowired to work with services defined in spring context.
In this case I personally use regular setUp() method annotated with #Before annotation and manage my custom static(!) boolean flag:
private static boolean setUpIsDone = false;
.....
#Before
public void setUp() {
if (setUpIsDone) {
return;
}
// do the setup
setUpIsDone = true;
}
You can use the BeforeClass annotation:
#BeforeClass
public static void setUpClass() {
//executed only once, before the first test
}
JUnit 5 now has a #BeforeAll annotation:
Denotes that the annotated method should be executed before all #Test
methods in the current class or class hierarchy; analogous to JUnit
4’s #BeforeClass. Such methods must be static.
The lifecycle annotations of JUnit 5 seem to have finally gotten it right! You can guess which annotations available without even looking (e.g. #BeforeEach #AfterAll)
When setUp() is in a superclass of the test class (e.g. AbstractTestBase below), the accepted answer can be modified as follows:
public abstract class AbstractTestBase {
private static Class<? extends AbstractTestBase> testClass;
.....
public void setUp() {
if (this.getClass().equals(testClass)) {
return;
}
// do the setup - once per concrete test class
.....
testClass = this.getClass();
}
}
This should work for a single non-static setUp() method but I'm unable to produce an equivalent for tearDown() without straying into a world of complex reflection... Bounty points to anyone who can!
JUnit 5 #BeforeAll can be non static provided the lifecycle of the test class is per class, i.e., annotate the test class with a #TestInstance(Lifecycle.PER_CLASS) and you are good to go
Edit:
I just found out while debugging that the class is instantiated before every test too.
I guess the #BeforeClass annotation is the best here.
You can set up on the constructor too, the test class is a class after all.
I'm not sure if it's a bad practice because almost all other methods are annotated, but it works. You could create a constructor like that:
public UT () {
// initialize once here
}
#Test
// Some test here...
The ctor will be called before the tests because they are not static.
Use Spring's #PostConstruct method to do all initialization work and this method runs before any of the #Test is executed
Try this solution:
https://stackoverflow.com/a/46274919/907576 :
with #BeforeAllMethods/#AfterAllMethods annotation you could execute any method in Test class in an instance context, where all injected values are available.
My dirty solution is:
public class TestCaseExtended extends TestCase {
private boolean isInitialized = false;
private int serId;
#Override
public void setUp() throws Exception {
super.setUp();
if(!isInitialized) {
loadSaveNewSerId();
emptyTestResultsDirectory();
isInitialized = true;
}
}
...
}
I use it as a base base to all my testCases.
If you don't want to force a declaration of a variable that is set and checked on each subtest, then adding this to a SuperTest could do:
public abstract class SuperTest {
private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
protected final boolean initialized() {
final boolean[] absent = {false};
INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
return absent[0] = true;
});
return !absent[0];
}
}
public class SubTest extends SuperTest {
#Before
public void before() {
if ( super.initialized() ) return;
... magic ...
}
}
I solved this problem like this:
Add to your Base abstract class (I mean abstract class where you initialize your driver in setUpDriver() method) this part of code:
private static boolean started = false;
static{
if (!started) {
started = true;
try {
setUpDriver(); //method where you initialize your driver
} catch (MalformedURLException e) {
}
}
}
And now, if your test classes will extends from Base abstract class -> setUpDriver() method will be executed before first #Test only ONE time per run.
Here is one alternative suggestion:
What I do to get this working is
Create a method named _warmup or just _
Annotate the test class with #FixMethodOrder(MethodSorters.NAME_ASCENDING)
This is applicable only if you run all tests in the class
It has a downside of having additional test included, which will also run one additional #Before and #After
It is usually advised for your test methods to be order independent, this breaks that rule, but why someone would like tests ordered randomly in the reports I have no clue so NAME_ASCENDING is what I always use
But the upsides to this is simple setup with minimal code and without the need to extend classes/runners etc...
Test run lengths are more accurate since all setup time is reported on method _warmup
After experimenting for some time this is my solution. I needed this for spring boot test. I tried using #PostConstruct, unfortunately it is executed for every test.
public class TestClass {
private static TestClass testClass = null;
#Before
public void setUp() {
if (testClass == null) {
// set up once
...
testClass = this;
}
}
#AfterClass
public static void cleanUpAfterAll() {
testClass.cleanUpAfterAllTests();
}
private void cleanUpAfterAllTests() {
// final cleanup after all tests
...
}
#Test
public void test1() {
// test 1
...
}
#Test
public void test2() {
// test 2
...
}
}
The problem with #BeforeClass is that it fires before the constructor.
So if you rely on an #Autowired constructor to provide data, it simply will not work: wrong execution order.
Similarly #PostConstruct fires after the constructor has been called. And the constructor fires with every #Test, therefore your setup function will fire with every test, if you use this.
This has the exact same effect as calling a function from the constructor.
The only solution, I found that works, is to use a flag to indicate if the setUp() method has already been executed. While its not ideal, it will drastically reduce the amount of processing before each test.
private static boolean initialized = false;
#Autowired
public CacheTest( MyBean myBean ){
this.myBean = myBean;
}
#PostConstruct
public static void setUp(){
if( initialized ) { return };
initialized = true;
//do suff with myBean
}

Categories