How to mock a protected static inner class with PowerMockito - java

I have a public outer class with a protected static inner class that I need to mock out for unit testing. We are using Mockito and PowerMockito but I have not been able to find anything in this vein during my searches. Does anyone have any ideas? Refactoring the inner class to be outside of the class and be public or anything of the sort is out of the question as of now as well.

Given a structure similar to
public class OuterClass {
public OuterClass() {
new InnerClass();
}
protected static class InnerClass {
public InnerClass() {
throw new UnsupportedOperationException("Muahahahaha!"); // no touchy touchy!
}
}
}
... you should be able to do the following
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertNotNull;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;
#RunWith(PowerMockRunner.class) // delegate test running to PowerMock
#PrepareForTest(OuterClass.class) // mark classes for instrumentation so magic can happen
public class InnerClassTest {
#Test
public void shouldNotThrowException() throws Exception { // oh, the puns!
// make a mockery of our inner class
OuterClass.InnerClass innerClassMock = mock(OuterClass.InnerClass.class);
// magically return the mock when a new instance is required
whenNew(OuterClass.InnerClass.class).withAnyArguments().thenReturn(innerClassMock);
// yey, no UnsupportedOperationException here!
OuterClass outerClass = new OuterClass();
assertNotNull(outerClass);
}
}

Related

How to use argumentcaptor to capture arguments passed to a constructor?

Say I have an outer class and an inner class set up like this:
public class OuterClass {
public static class InnerClass {
private String data; //no getter exists
public InnerClass(String arg) {
data = arg;
}
//...
}
public InnerClass functionUnderTest(String foo) {
return new InnerClass(foo);
}
//...
}
In order to not break other code, I cannot change the structure of the classes here. I also do not want to add a public getter to InnerClass as I feel this would break the intended encapsulation purely for testing purposes.
What I want to do is test the function functionUnderTest and make sure that the argument it is feeding to the InnerClass constructor really is foo. I have my reasons for wanting to test this.
My approach was to use an argumentcaptor from Mockito to try to capture the arguments fed to the constructor. Here is the test class I wrote:
public class OuterClassTest {
import org.junit.Before;
import org.junit.Test;
import org.junit.Assert;
import org.mockito.*;
import static org.mockito.Mockito.verify;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testFunction() {
ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
OuterClass myclass = new OuterClass();
verify(myclass).new InnerClass(stringArgumentCaptor.capture());
String test = "haha";
myclass.functionUnderTest(test);
Assert.assertEquals(test, stringArgumentCaptor.getValue());
}
}
But there is a problem. This gives me an error: "Argument passed to verify() is of type OuterClass and is not a mock!"
I don't want to use a mock for this though, because what is the point of mocking the class and thereby the function that I'm trying to test.
I believe that because InnerClass is public and static, I don't need the OuterClass object myclass to call new InnerClass(...). But I don't really know how else to capture the arguments fed to the InnerClass constructor by myclass.functionUnderTest(). Is there a way to do this with argumentcaptor?

How to mock a nested function?

I have this following class A. It has two functions Barney and Ted. Barney calls Ted from inside. How to mock Ted's behavior in my test class?
package MockingNestedFunction;
import java.util.ArrayList;
import java.util.List;
public class A
{
public String Barney()
{
List<String> x =Ted();
String a="";
for(int i=0;i<x.size();i++)
{
a=a.concat(x.get(i));
}
return a;
}
public List<String> Ted()
{
List<String> x=new ArrayList<>();
x.add("A");
x.add("B");
x.add("C");
return x;
}
}
package MockingNestedFunction;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.when;
import static org.testng.Assert.*;
public class ATest
{
private A a;
#BeforeMethod
public void setup()
{
MockitoAnnotations.openMocks(this);
a=new A();
}
#Test
public void testA() throws Exception
{
List<String> x=new ArrayList<>();
x.add("D");
x.add("E");
x.add("F");
when(a.Ted()).thenReturn(x);
}
}
when(a.Ted()).thenReturn(x) returns the error,when() requires an argument which has to be 'a method call on a mock'.
How to effectively mock this?
You dont pass a method call on a mock to Mockito.when, as error message helpfully says. You are passing a method call on a object you created yourself.
If you need to stub some methods of the object under test, you are looking for a spy.
#Spy
private A a;
#BeforeMethod
public void setup() {
MockitoAnnotations.openMocks(this);
}
As others noted in comments, stubbing some methods on object under test is a questionable practice, if you can think about restructuring the code.
On top of that: Let's keep the terminology precise. There are no nested functions in your code.

Static import or plain import of a static nested class

I know that the traditional import statement is for classes and the import static statement is for static members. But what should you use for static nested classes?
Consider:
public class MyUtilityClass {
public static class SomeNestedClass {
//...
}
public static class AnotherNestedClass {
//...
}
}
With usage:
import MyUtilityClass.AnotherNestedClass;
import static MyUtilityClass.SomeNestedClass;
public class Main {
public static void main(String[] args) {
SomeNestedClass a = new SomeNestedClass();
AnotherNestedClass b = new AnotherNestedClass();
}
}
You see, both import and import static statements can be used. But which one is more correct, or more typical, or recommended by most coding guidelines?
As general best practice, static import should be used for Members, and import for Classes.
From the java documentation for static import:
Where the normal import declaration imports classes from packages, allowing them to be used without package qualification, the static import declaration imports static members from classes, allowing them to be used without class qualification.

How To Set Up PowerMockito To Verify Different Types of Methods Are Called?

Please provide minimal examples of using PowerMockito to test public, public static, private, and private static methods.
Here's an extremely stripped down example ("SSCCE") of using PowerMockito to verify four types of methods have been called from another method: public, public static, private, and private static.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(com.dnb.cirrus.core.authentication.TestableTest.Testable.class)
public class TestableTest {
public static class Testable {
public void a() {
b();
c();
d();
e();
}
public void b() {
}
public static void c() {
}
private void d() {
}
private static void e() {
}
}
Testable testable;
// Verify that public b() is called from a()
#Test
public void testB() {
testable = Mockito.spy(new Testable());
testable.a();
Mockito.verify(testable).b();
}
// Verify that public static c() is called from a()
#Test
public void testC() throws Exception {
PowerMockito.mockStatic(Testable.class);
testable = new Testable();
testable.a();
PowerMockito.verifyStatic();
Testable.c();
}
// Verify that private d() is called from a()
#Test
public void testD() throws Exception {
testable = PowerMockito.spy(new Testable());
testable.a();
PowerMockito.verifyPrivate(testable).invoke("d");
}
// Verify that private static e() is called from a()
#Test
public void testE() throws Exception {
PowerMockito.mockStatic(Testable.class);
testable = new Testable();
testable.a();
PowerMockito.verifyPrivate(Testable.class).invoke("e");
}
}
Some pitfalls to be aware of:
PowerMockito and Mockito both implement spy() as well as other methods. Make sure to use the correct class for the situation.
Incorrectly set up PowerMockito tests often pass. Be sure the test can fail when it should (checked for in the above code by commenting out "testable.a()").
Overridden PowerMockito methods take either Class or Object as parameters which are used in static and non-static contexts respectively. Make sure to use the correct type for the context.

Codemodel does not generate static import

JCodeModel generates an import statement in place of an import static. For example I have a class that has import nz.co.cloudm.cloudserv.api.pojos.core.file.attachment.Attachment.Status instead of import static nz.co.cloudm.cloudserv.api.pojos.core.file.attachment.Attachment.Status so the compiler throws an error. The class Status is an inner enum that lives in the Attachment class as you can see in the import statement.
Do you know any way I can achieve an import static using code model?
Or otherwise how make the member to use the class qualified name?
private nz.co.cloudm.cloudserv.api.pojos.core.file.attachment.Attachment.Status status;
I'm not sure codemodel has the ability to define static imports, as it's an older library. You can use the enum though just through the ref() method since static imports are really just a programmer's convenience:
public class Tester {
public enum Status{
ONE, TWO;
}
public static void main(String[] args) throws JClassAlreadyExistsException, IOException {
JCodeModel codeModel = new JCodeModel();
JClass ref = codeModel.ref(Status.class);
JDefinedClass outputClass = codeModel._class("Output");
outputClass.field(JMod.PRIVATE, ref, "status", ref.staticRef(Status.ONE.name()));
codeModel.build(new StdOutCodeWriter());
}
}
Outputs:
public class Output {
private test.Tester.Status status = test.Tester.Status.ONE;
}

Categories

Resources