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.
Related
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?
I have the abstract class and subclass:
A.java:
package myPackage;
import java.util.ArrayList;
import java.util.List;
public abstract class A {
protected abstract int getInt();
protected List<Integer> get10Int() {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
list.add(getInt());
}
return list;
}
}
AImp.java:
package myOtherPackage;
import myPackage.A;
public class AImp extends A {
#Override
protected int getInt(){
return 1;
}
}
I define a test in the same package as the subclass:
package myOtherPackage;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class AimpTest {
#Test
public void testProtectedMethodFromSuperClass(){
AImp aimp = new AImp();
assertEquals(aimp.get10Int().size(), 10);
}
}
and I get an error because get10Int() has protected access in myPackage.A. Is there any way I can test this method (which is an inherited method of a superclass in another package) while keeping AImp and AImpTest in myOtherPackage, and also keeping the superclass in its own package?
I would personally create a test for class A, in your test use a dummy implementation and then test out your function. This way the test is not required on every implementation.
I agree with the other answer in that you should write a Test for the class A in it's package, because what you are testing is functionality of A and not AImp, but if you really want to access protected (or even private) methods you can do it like this:
#Test
public void testProtectedMethodFromSuperClass(){
AImp aimp = new AImp();
Method get10IntMethod = AImp.class.getDeclaredMethod("get10Int");
get10IntMethod.setAccessible(true);
List<Integer> result = (List<Integer>) get10IntMethod.invoke(aimp);
assertEquals(result.size(), 10);
}
And if you want to call a method with arguments (e.g. otherMethod(int)) you have to pass the argument types to getDeclaredMethod() like this: getDeclaredMethod("otherMethod", int.class)
and the arguments to invoke: method.invoke(instance, 5).
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.
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);
}
}
I'm trying to write unit tests with Mockito / JUnit for a function like this:
class1 {
method {
object1 = class2.method // method that I want to fake the return value
// some code that I still want to run
}
}
Is there any way in Mockito to stub the result of class2.method? I'm trying to improve code coverage for class1 so I need to call its real production methods.
I looked into the Mockito API at its spy method but that would overwrite the whole method and not the part that I want.
I think I am understanding your question. Let me re-phrase, you have a function that you are trying to test and want to mock the results of a function called within that function, but in a different class. I have handled that in the following way.
public MyUnitTest {
private static final MyClass2 class2 = mock(MyClass2.class);
#Begin
public void setupTests() {
when(class2.get(1000)).thenReturn(new User(1000, "John"));
when(class2.validateObject(anyObj()).thenReturn(true);
}
#Test
public void testFunctionCall() {
String out = myClass.functionCall();
assertThat(out).isEqualTo("Output");
}
}
What this is doing is that within the function wrapped with the #Before annotation, I am setting up how I want the functions in class2 to respond given specific inputs. Then, from within the actual test, I am just calling the function that I am trying to test in the class I want to test. In this case, the myClass.functionCall() is running through as normal and you are not overwriting any of its methods, but you are just mocking the outputs that it gets from the methods (or method) within MyClass2.
This Worked for Me:
public class Class1Test {
Class1 class1;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
class1 = new Class1();
}
#Test
public void testClass1Method() {
Class2 class2 = Mockito.mock(Class2.class);
class1.setClass2(class2);
Mockito.when(
class2.class2Method(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn("some response");
String actualResponse = class1
.class1Method("12345", "3333", "4444");
assertEquals("some response", actualResponse);
}
}
I wrote a simple example which worked fine, hope it helps:
method1() from Class1 calls method2() from Class2:
public class Class1 {
private Class2 class2 = new Class2();
public int method1() {
return class2.method2();
}
}
Class2 and method2() :
public class Class2 {
public int method2() {
return 5;
}
}
And the Test:
import org.junit.Rule;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
public class TestClass1 {
#Mock
Class2 class2;
#InjectMocks
Class1 class1;
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Test
public void testMethod1(){
when(class2.method2()).thenReturn(29);
assertEquals(29,class1.method1());
}
}