Mockito thenCallRealMethod method calls other mocked class as real - java

I have a class with two methods and i want to test one of them but it uses the other method. Therefore, i have to use Mock annotation to mock all methods and use thenCallRealMethod to test my method. I applied this approach and it worked. But, i faced an another problem. The problem is caused by my testing method which wrapped by thenCallRealMethod. It didn't use Mocked classes and invoked real classes. So, it caused null pointer error. Thanks for any comments.
Test
...
#Mock
ClassA a;
#Mock
ClassB b;
#Test
public void testing() {
Mockito.when(ClassB.methodX()).thenReturn(x);
Mockito.when(ClassA.methodZ()).thenReturn(Mockito.Any());
Mockito.when(ClassA.methodY()).thenCallRealMethod();
ClassA.methodY();
}
...
ClassA
...
#Autowired
ClassB b;
public byte[] methodZ(){
...
}
public void methodY(){
b.methodX();
methodZ();
}
...

Related

Injecting multiple implementations of same interface through Instance<T> in test class

I'm struggling with writing unit tests for one of my classes. The main class:
public class MainClass {
...
private Instance<BaseInterface> steps;
#Inject
public void setSteps(Instance<BaseInterface> steps) { this.steps = steps; }
#Asynchronous
public void callingMethod() {
...
ImmutableList<BaseInterface> stepList = STEP_ORDERING.immutableSortedCopy(steps); // Here the NPE is being thrown when calling method from test class
...
}
}
There are 5 specific implementations of BaseInterface, all 5 are correctly injected through setter by CDI at runtime (one of the implementation is annotated with #Named, the rest do not have this annotation).
However, calling the wrapper method callingMethod from the test class throws NPE. The test class:
#RunWith(MockitoJUnitRunner.class)
public class MainClassTest {
#InjectMocks
private MainClass mainClass = new MainClass();
#Mock
private Instance<BaseInterface> steps;
#Test
public void test() {
...
mainClass.callingMethod(); // Throws NPE
...
}
}
As far as I'm concerned, Mockito does not take care of bean dependency injection like CDI. Therefore, is there a way in which to tell Mockito to mock all implementations of BaseInterface and inject them into the MainClass?
Version details: Java 8, Mockito 2.8.9, JUnit 4
Thank you!
Solved. The problem was not caused by Mockito, but by the method STEP_ORDERING.immutableSortedCopy which behind the scenes calls iterator() method from Instance<T> which returned null (since it extends Iterable<T>).
Mocking the iterator does the trick:
Iterator<BaseInterface> iteratorMock = (Iterator<BaseInterface>) mock(Iterator.class);
when(steps.iterator()).thenReturn(iteratorMock);
or by creating an actual instance of iterator:
Iterator<BaseInterface> iteratorActual = new Iterator<BaseInterface>(){
// implementation here
};
when(steps.iterator()).thenReturn(iteratorActual );

Mockito: mocking a method of same class called by method under test when using #InjectMocks

I have a class I want to test that has several external dependencies, and a couple internal methods. I would like to write a test for MethodA, but not have Method A's internal call to MethodB to actually exercise MethodB. I'd like to mock/stub MethodB and return something specific instead. Usually I'd use when/thenReturn but it doesn't behave like I expect - it actually jumps into Method B while creating the mock itself.
MyService.java
#Service
public class MyService {
#Autowired
private ServiceA serviceA;
#Autowired
private ServiceB serviceB;
public SomeObject methodA() {
// some logic using serviceA.method and serviceB.method that creates "output"
SomeObject someObject = methodB(output);
return someObject;
}
public SomeObject methodB(SomeObject someObject) {
// deep mysteries done here to someObject
return someObject
}
}
MyServiceTest.java
public class MyServiceTest {
#Mock
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#InjectMocks
private MyService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void methodATest() {
when(serviceA.method()).thenReturn(stuff);
when(serviceB.method()).thenReturn(otherStuff);
// here is what I would like to do
when(myService.methodB()).thenReturn(mockedSomeObject); //<- doesn't work
assertThat(myService.methodA().getSomeObjectProperty())
.isEqualTo("property");
}
}
I've looked at solutions that manually mock the MyService class with Mockito.mock(MyService.class), but (as the above example is obviously contrived) my actual class has quite a few external dependencies and I'd prefer a solution that still allows me to mock the service using #Mock for the #Autowired dependencies and #InitMocks for the class under test, unless it's simply not possible.
I've tried:
Mockito.doReturn(mockedSomeObject).when(myService.methodB(any(SomeObject.class));
but that also steps into MethodB when creating the mock for that method, which shouldn't be happening.
Thanks in advance for the help!
Try Adding #Spy to your InjectMocks and use the object to "expect" them in a slightly different syntax.
import org.mockito.Spy;
#InjectMocks
#Spy
private MyService myService;
And now mock the service call
Mockito.doReturn(mockedSomeObject).when(myService).methodB();
Also change the other mock call to this
Mockito.doReturn(stuff).when(serviceA).method();
Mockito.doReturn(otherStuff).when(serviceB).method();
You need to mark your object as Spy or explicitly create a Spy object for it using MyClass objA=null;
MyClass spy_objA=Powermockito.spy(objA)
doReturn(what_you_want).when(spy_objA).method()
Edit: Can find a similar question you may want to check
How to mock another method in the same class which is being tested?

Mockito Not Able to Mock function call present in target class's constructor

I am trying to test the following class using Mockito and JUnit :
public class A {
private SomeClass someObject;
private SomeImpClass someImpObject1;
private SomeImpClass2 someImpObject2;
public A(SomeImpClass someImpObject1, SomeImpClass2 someImpObject2){
someObject = makeNewObject(someImpObject1, someImpObject2);
}
public makeNewObject(SomeImpClass1 someImpObject1, SomeImpClass2 someImpObject2){
return new SomeObject(someImpObject1,someImpObject2);
}
public usingSomeObject(){
someObject.doSomething();
}
}
So, I wrote a Unit Test using Mockito and JUnit :
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
SomeImpClass1 someImpObject1;
#Mock
SomeImpClass2 someImpObject2;
#Mock
SomeObject someObject;
#Spy
A a;
#Before
public void setUp() {
when(A.makeNewObject).thenReturn(someObject);
this.A = new A(this.someImpObject1, someImpObject2);
when(someObject.doSomething).thenReturn(something);
}
}
The Issue I am facing here is, although I have stubbed the function makeNewObject to return a Mocked object of SomeClass, the code flow is still going inside the fucntion (makeNewObject) and giving a null exception.
What Am I Doing Wrong ?
I have wasted a day behind this.
Not Very Fluent with Mockito.
You wont be able to achieve what you are aiming for with spying and stubbing.
This is because your aiming at stubbing a method used in a constructor.. but you cannot start stubbing once you created a concrete object and spy it.. can't be done..
I would suggest creating a private class inside the test class which extends your class under test, override the method invoked in the constructor and then use it in your tests:
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
SomeObject someObjectMock;
A a;
#Before
public void setUp() {
this.a = new MyTest();
}
private class MyTest extends ATest{
#Override
public makeNewObject(SomeImpClass1 someImpObject1, SomeImpClass2 someImpObject2){
return someObjectMock;
}
}
Now you dont need to use spying and stubbing of it also as the overriden method is always returning what you expect in the test.

PowerMockito using InjectMocks error

I have a very complicated class to write Junit test case. I decided to use PowerMockito since my class for which the test is to be run has a constructor initialization.
My main class is like this:
public class MainClass extends BaseClass{
MainClass(SomeClass class){
super(class);
}
public void methodToBeTested(){
some code here
}
..few other methods which I am not going to test.
}
Now I have the test case written like this:
#RunWith(PowerMockRunner.class)
public class TestClass{
#Mock
OtherClassUsedInMainClass mock1;
#Mock
OtherClassUsedInMainClass mock2;
#InjectMocks
MainClass mainClass;
#Before
public void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
PowerMockito.whenNew(MainClass.class).withArguments(Mockito.any(SomeClass.class))
.thenReturn(mainClass);)
}
#Test
public void testMethodtobeTested(){
...I am using the other objects to mock data and test if this method works fine
mainClass.methodtobeTested();
\\This method will increment a value. I am just asserting if that value is right.
Assert.assertEquals(mainClass.checkCount(),RequiredCount)
}
}
I am getting a null pointer exception when running the Testcase since it tries to initialize the mainClass. It does not get mocked. I know I am doing something wrong. But I just don't know what it is.
Error:
org.mockito.exceptions.base.MockitoException:
Cannot instantiate #InjectMocks field named 'mainClass' of type 'class com.main.MainClass'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null
Caused by: java.lang.NullPointerException
This null pointer exception is thrown from a the constructor of the BaseClass when it tries to initialize another class.
This question explains the difference between #Mock and #InjectMocks:
#Mock creates a mock. #InjectMocks creates an instance of the class and injects the mocks that are created with the #Mock (or #Spy) annotations into this instance.
MainClass constructor expects a SomeClass parameter but there isn't any mock for that.
Your code should be something like:
#RunWith(PowerMockRunner.class)
public class TestClass{
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
SomeClass mock1;
#InjectMocks
MainClass mainClass;
#Before
public void setUp() throws Exception{
...
Quoting this answer, which is quoting the #InjectMocks documentation:
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. Note: If arguments can not be found, then null is passed.
So, presumably, declare a field of type SomeClass, and annotate it #Mock.
If you can't show us the actual code it is very hard to guess what exactly is happening. But it looks like your mock SomeClass needs some stubbed behavior to satisfy the BaseClass constructor.
For example:
// the instance of MainClass you run your tests against
private MainClass instance;
#Mock
private SomeClass someClass;
#Mock
private SomethingElse somethingElse;
#Before
public void setUp() {
when(someClass.doSomething()).thenReturn(somethingElse);
instance = new MainClass(someClass);
}
#Test
public void test() {
// SETUP
when(somethingElse.doWeirdStuff()).thenThrow(new WeirdException());
// CALL
instance.performTapDance();
// VERIFY
assertTrue(instance.isWeird());
}

Applying multiple permutations of mocks to dependencies for better unit testing in Spring

Let's say I have a class (OrchestratingClass) that has a method orchestrate() that calls a number of smaller methods of other classes (classA's do1() method, classB's do2() method). I would like to test the behavior of orchestrate() by mocking the responses of do1() and do2() with various permutations. I'm running my test with something like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public OrchestratingClassTest {
#Inject
private OrchestratingClass oc;
#Test
public void test1() {
// I would like to mock classA's do1() method to send back "1"
// I would like to mock classB's do2() method to send back "2"
}
#Test
public void test2() {
// I would like to mock classA's do1() method to send back "100"
// I would like to mock classB's do2() method to send back "200"
}
static class SimpleConfig {
#Bean
public InterfaceA interfaceA() {
return new ClassA();
}
#Bean
public InterfaceB interfaceB() {
return new ClassB();
}
#Bean
public OrchestratingClass orchestratingClass() {
return new OrchestratingClass();
}
}
}
And the orchestratingClass itself is quite basic, but I've added some sample code to aid in visualization:
#Named
public OrchestratingClass {
#Inject
private InterfaceA interfaceA;
#Inject
private InterfaceB interfaceB;
public String orchestrate() {
return interfaceA.do1() + " " + interfaceB.do2();
}
}
Now I'm aware I could tweak my SimpleConfig class to have the mocked out versions of classA and classB, but then I'm locked into 1 particular mock and can't "re-mock" things when I move onto test2(). I'm convinced that playing around with the java config files for 1 single test class would not work if we're trying to inject different "flavors" of beans "per-test". Does anyone have any recommendation on what I can do to make sure I'm really testing this thoroughly without being invasive (ex: adding superfluous "setters" for the specific classes in the orchestratingClass to side-step the bean injection pain)? Essentially, I'm looking to "tamper" the applicationContext on a per-test basis for specific beans of interest (along with the necessary housekeeping that's required) by applying a variety of mocks.
Here's a simple example using Mockito:
public class OrchestratingClassTest {
#Mock
private ClassA mockA;
#Mock
private ClassB mockB;
#InjectMocks
private OrchestratingClass oc;
#Before
public void prepare() {
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldConcatenate() {
when(mockA.do1()).thenReturn("1");
when(mockB.do2()).thenReturn("2");
assertEquals("1 2", oc.orchestrate());
}
}
The magic happens in the call to MockitoAnnotations.initMocks(this), which will create mock instances for the fields annotated with #Mock, then create a real instance of Orchestrating class and inject its fields, thanks to #InjectMocks.
Note that, even without this magic, you could make your class easily testable by just adding a constructor taking ClassA and ClassB as arguments to OrchestratingClass, and annotate that constructor with #Autowired instead of annotating the fields. So, in short, use constructor injection rather than field injection.

Categories