PowerMock(with mockito) simple unit test error - unit-testing

I am using Mockito + PowerMock to write a simple unit test for the following singleton class:
public class MyService {
private static MyService service;
private List<School> schoolList;
private MyService(){
// test case error complains here!
School school = new School();
schoolList.add(school);
}
public static Singleton getInstance( ) {
return service;
}
protected static void printSchool( ) {
School school = schoolList.get(0);
print(school);
}
}
My Test case:
#RunWith(PowerMockRunner.class)
public class MyServiceTest {
#PrepareForTest({MyService.class})
#Test
public void testPrintSchool() {
// enable mock static function
PowerMockito.mockStatic(MyService.class);
MyService mockService = PowerMockito.mock(MyService.class);
PowerMockito.when(MyService.getInstance())
.thenReturn(mockService);
}
}
I run my test, but got the following error:
java.lang.RuntimeException: Invoking the beforeTestMethod method on PowerMock test listener org.powermock.api.extension.listener.AnnotationEnabler#3ab19451 failed.
at com.xyz.MyService.<init>(MyService.java:12)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.mockito.internal.util.reflection.FieldInitializer$ParameterizedConstructorInstantiator.instantiate(FieldInitializer.java:257)
at org.mockito.internal.util.reflection.FieldInitializer.acquireFieldInstance(FieldInitializer.java:124)
at org.mockito.internal.util.reflection.FieldInitializer.initialize(FieldInitializer.java:86)
at org.mockito.internal.configuration.injection.ConstructorInjection.processInjection(ConstructorInjection.java:52)
...
As you can see, the error complains about MyService.java:12 line 12, that is the line School school = new School(); in MyService constructor.
Why I get this error, how to get rid of it?

#PrepareForTest({MyService.class}) is a class level annotation.
You should add it at the same location as #RunWith(PowerMockRunner.class)
You can find more information at their github

Related

Why is #Inject object(Optional) coming null while running unit test?

I have a class Room, where I inject Optional Person object, this is coming null while running testSuccess. My understanding is it should come non null, since I am setting this to new Person() at the start of the test. Why is it coming null?
public class Room{
#Inject
private Optional<Person> person1
//this is coming null when running test
}
My unit test
public class RoomTest {
#Inject Mocks
private Room testRoom
.....
//Other mocks
private Optional<Person> testPerson
//Not able to mock this since its optional, hence directly setting value in unit test.
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSuccess() {
testPerson = Optional.of(new Person());
....
}
}
As the name implies, #InjectMocks only injects #Mocks. The testPerson is not a mock. Why not just add an #Inject-ing constructor to the Room class that would accept a person? This way you could just instantiate a testRoom in your test method and your dependency injection will still work.
public class Room{
private Optional<Person> person;
#Inject
public Room(Optional<Person> person) {
this.person = person;
}
}
public class RoomTest {
#Test
public void testSuccess() {
Optional<Person> testPerson = Optional.of(new Person());
Room room = new Room(testPerson);
...
}
}
That said, if you absolutely want to use the annotations and adding the constructor is not an option for you then you can use PowerMock runner to mock the Optional. Conceptually, it can look like the code below. But usually, if you have to use PowerMock there might be something wrong with the code :)
public class Room{
#Inject
private Optional<Person> person;
}
// This is for JUnit4. Using Powermock with JUnit5 will be more involved
#RunWith(PowerMockitoRunner.class)
#PrepareForTest(Optional.class) // to mock the final class
public class RoomTest {
#InjectMocks
private Room testRoom;
#Mock
private Optional<Person> testPerson;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSuccess() {
...
}
}

unit tests which need CDI container result in java.lang.IllegalStateException: Unable to access CDI

I'm using Weld for CDI.
I'm trying to write a unit test for service "A" using JUnit 5.
The constructor of service A is:
#Inject
public A (B b) {this.b = b}
Class B constructor is:
#ApplicationScoped
public class B{
private C c;
public B() {
c = CDI.current().select(C.class).get();
}
}
When i try to mock Class B during unit tests i get:
java.lang.IllegalStateException: Unable to access CDI
because during unit tests there isn't a proper CDI container.
How can resolve this issue? is there anyway to it with Mockito? (let's assume that replacing the CDI.current() is not an option)
This how the test code looks:
public class ATest {
private A a;
#WeldSetup
private WeldInitiator weld = WeldInitiator.from(A.class)
.addBeans(createBBean()).build();
private Bean<?> createBBean() {
return MockBean.builder()
.types(B.class)
.scope(ApplicationScoped.class)
.creating(new B())
.build();
}
#BeforeEach
void setUpClass() {
a = weld.select(A.class).get();
}
}
I always do this (CDI 2.0 and later):
private SeContainer container;
#BeforeEach
private void startContainer() {
SeContainerInitializer initializer = SeContainerInitializer.newInstance();
// add what you want, disable discovery, whatever
this.container = initializer.initialize();
}
#AfterEach
private void stopContainer() {
if (this.container != null) {
this.container.close();
}
}
Then any #Test has access to CDI.

ClassNotFound exception when mocking static classes with PowerMockito

I have a project by name Utility and it has a class by name Util as below:
public class Util {
public static String verify() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet getRequest = new HttpGet("Endpoint");
HttpResponse response = httpClient.execute(getRequest);
// Parsing the response as String
String resp = .......
return resp;
}
}
I have another project by name Consumer and it has a class by name Service as below:
public class Service {
public String verify() {
String resp = Util.verify();
return resp;
}
}
I have added Utility as a dependency for Consumer as:
<dependency>
<groupId>com.my.company</groupId>
<artifactId>utility</artifactId>
<version>0.0.1</version>
<scope>provided</scope>
</dependency>
I have a unit test case for the Service class where I am mocking the Util class with PowerMockito as:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ Util.class })
public class ServiceTest {
Service service = new Service();
#Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Util.class);
PowerMockito.when(Util.verify()).thenReturn("mockedResponse");
}
#Test
public void testVerify() {
String resp = service.verify();
assertEquals(resp, "mockedResponse");
}
}
This test throws NotFoundException for ProtocolSocketFactory. Does anyone know why I see this exception? I am trying to mock the Util class, but PowerMockito tries to initialize the class before mocking it. If I add HttpClient as a dependency in pom.xml for project Consumer, then the error goes away and the mocking is successful.
The Powermockito version I am using is 1.6.2
java.lang.IllegalStateException: Failed to transform class with name com.my.company.Util. Reason: cannot find org.apache.commons.httpclient.protocol.ProtocolSocketFactory
at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:266)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:180)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:68)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114)
Caused by: javassist.CannotCompileException: cannot find org.apache.commons.httpclient.protocol.ProtocolSocketFactory
at javassist.expr.NewExpr.replace(NewExpr.java:215)
at org.powermock.core.transformers.impl.MainMockTransformer$PowerMockExpressionEditor.edit(MainMockTransformer.java:418)
at javassist.expr.ExprEditor.loopBody(ExprEditor.java:212)
at javassist.expr.ExprEditor.doit(ExprEditor.java:91)
at javassist.CtClassType.instrument(CtClassType.java:1431)
at org.powermock.core.transformers.impl.MainMockTransformer.transform(MainMockTransformer.java:74)
at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:251)
... 55 more
Caused by: javassist.NotFoundException: org.apache.commons.httpclient.protocol.ProtocolSocketFactory
at javassist.ClassPool.get(ClassPool.java:450)
at javassist.bytecode.Descriptor.toCtClass(Descriptor.java:592)
at javassist.bytecode.Descriptor.getParameterTypes(Descriptor.java:439)
at javassist.expr.NewExpr.replace(NewExpr.java:188)
... 61 more

JUnit Tests for Liferay MVCPortlet using PowerMock

Im trying to make JUnit Test using PowerMock, but I have one problem. Here is my code:
public class MyGreeting extends MVCPortlet {
public static final String GREETING="greeting";
private static final String DEFAULT_GREETING="MY DEFAULT GREETING MESSAGE";
private static final Log _log = LogFactoryUtil.getLog(MyGreeting.class.getName());
#Override
public void render(RenderRequest req,RenderResponse res)
throws IOException, PortletException {
PortletPreferences prefs = req.getPreferences();
req.setAttribute(GREETING, prefs.getValue(GREETING, DEFAULT_GREETING));
super.render(req,res);
}
And I need to make JUnit test. I created another test package, new MyGreetingTest.java file, and come up to this code:
public class MyGreetingTest extends Mockito{
#BeforeClass
public static void setUpBeforeClass() throws Exception {
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
}
private MyGreeting portlet;
#Before
public void setUp() throws Exception {
portlet = new MyGreeting();
}
#After
public void tearDown() throws Exception {
}
#Mock
public RenderRequest request = mock(RenderRequest.class);
#Mock
PortletPreferences preferences = mock(PortletPreferences.class);
#Test
public final void renderTest() throws IOException, PortletException {
when(request.getPreferences()).thenReturn(preferences);
when(preferences.getValue(MyGreeting.GREETING, null)).thenReturn(value);
portlet.render(request, null);
String result = request.getAttribute(MyGreeting.GREETING).toString();
assertEquals(result, value);
}
But I have NullPointerException, because we can't apply getAttribute method to mock-request. Could you please tell me how to solve this problem? How can I test method with getAttribute method using Mockito?
I think you need to mock your method
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00); // Mock implementation
when(stock.getValue()).thenCallRealMethod(); // Real implementation

How to mock web service call without passing mocked class as parameter

I have a web serivce class which need to unit tested.
Here is class which is under test
public class ValidatePaymentMessage {
public CsmValidationResultX validatePaymentmsg(String csmName, String base64PayloadXML){
//Call Web Service to validate Payment
CsmValidationResultX responseMsg=null;
PaymentManagerWebService paymentManagerWebService = new PaymentManagerWebService();
PaymentManagerWebServiceImpl serviceAddrs = paymentManagerWebService.getPaymentManagerWebServicePort();
try {
responseMsg = serviceAddrs.validatePayment(csmName, base64PayloadXML);
} catch (MPMWebServiceException e) {
e.printStackTrace();
}
return responseMsg;
}
}
Here is my Junit class
public class ValidatePaymentMessageTest {
#Test
public void testValidatePaymentmsg() throws MPMWebServiceException {
CsmValidationResultX csmResult= EasyMock.createMock(CsmValidationResultX.class);
PaymentManagerWebServiceImpl paymentManagerImpl = EasyMock.createMock(PaymentManagerWebServiceImpl.class);
EasyMock.expect(paymentManagerImpl.validatePayment("SEPA","BASE64XML")).andReturn(csmResult).anyTimes();
PaymentManagerWebService paymentManager = EasyMock.createMock(PaymentManagerWebService.class);
EasyMock.expect(paymentManager.getPaymentManagerWebServicePort()).andReturn(paymentManagerImpl).anyTimes();
ValidatePaymentMessage validatePayment=new ValidatePaymentMessage();
CsmValidationResultX response = validatePayment.validatePaymentmsg("SEPA", "base64PayloadXML");
System.out.println(response.getCsmValidationResult().isValid());
}
}
When I run this Junit it is calling actual web service instead of mocked one's.So Please let me know how can i resolve this problem.
You are still instantiating a real PaymentManagerWebService in validatePaymentmsg(), so the mocks do not help. You can't mock construction of local variables with EasyMock, but you can with PowerMock. So if changing the code to receive and instance of PaymentManagerWebService is not an option, mock its construction with PowerMock.
#RunWith(PowerMockRunner.class)
#PrepareForTest(ValidatePaymentMessage.class)
public class ValidatePaymentMessageTest {
#Test
public void testValidatePaymentmsg() throws MPMWebServiceException {
// .....
PowerMock.expectNew(PaymentManagerWebService.class).andReturn(paymentManager);
//....
}
}