How to get constructor injection in Mockito
I have the following class:
class A {
private B mB;
A(B b) {
mB = b;
}
void String someMethod() {
mB.execute();
}
}
how do I test someMethod using a mock class A and class B using
B b = Mockito.mock(B.class)
Mockito.when(b.execute()).thenReturn("String")
A a = Mockito.mock(A.class)
//somehow inject b into A and make the below statement run
Mockito.when(a.someMethod()).check(equals("String"))
You need create real A class because you want to test it but you need to mock other classes used in A class. Also, you can find mockito documentation says that don't mock everything.
class ATest {
#Mock
private B b;
private A a;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
a = new A(b);
}
#Test
public String someMethodTest() {
String result = "result";
Mockito.when(b.execute()).thenReturn(result);
String response = a.someMethod();
Mockito.verify(b, Mockito.atLeastOnce()).execute();
assertEquals(response, result);
}
}
Another way of injecting a mock to real object (as A should be a real object) is to use annotations, they will create objects you want:
#Mock
B mockOfB;
#InjectMocks
A realObjectA;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
Then, like they said, run the method you want to test without mockito (because you want to test it, so call it on real instance) and check the result according to your expectations.
Behaviour of object B can be mocked in any way, to satisfy your needs.
You want to test someMethod() of class A. Testing the execute() of class B should take place in the other test, because instance of B is a dependency in your case. Test for execute() should be made in different test.
You don't need to test how B object will behave, so you need to mock it and afterwards, check that execute() was invoked.
So in your case your test will look something like this:
B b = Mockito.mock(B.class);
A a = new A( b );
a.someMethod();
Mockito.verify( b, Mockito.times( 1 ) ).execute();
In my opinion, you're mixing up two ways of testing.
If you want to write a test using Mockito, you just create a mock of some class and use it. This mock doesn't have anything related to a real object as you can (should) mock every method that is called in the test. That's why it doesn't make any sense to mock class B - it is simply not used by class A.
Otherwise, if you want to test a real behavior of class A then why do you want to mock it? Create a real instance of class A with a mocked instance of class B.
That's it! Don't mix it up.
Related
Let's assume I have an object like this:
public ClassA() {
public void start() {
...
ClassB something = getSomeStuff();
...
}
protected ClassB getSomeStuff() {
return new ClassB(render, response);
}
}
Then I'm trying to do some unit-testing like this where I do a spy on a method-call on a spied object:
#Spy private ClassA classA;
#Mock private ClassC classC;
...
#Test
void test1() {
ClassB classB = spy(classA.getSomeStuff());
doReturn(classC).when(classB).getResults();
classA.start();
}
When I run this test and it comes down to this last line, I can see in my debugger that it is not returning classC.
Is this because it is not possible to do nested spying? Or is somehting wrong in my setup? Or should I approach this differently?
Details:
junit: 5.7.0
mockito: 3.12.4
When we look at the code presented, we see that calling classA.getSomeStuff() will return a new instance of ClassB with every call, i.e. classA.getSomeStuff() == classA.getSomeStuff() will evaluate to false.
What does that mean for our test setup? We construct a spy:
ClassB classB = spy(classA.getSomeStuff());
but this spy is never used. When we call classA.start(), it will call classA.getSomeStuff() again, and a new (non-spy) ClassB-instance is returned.
This is an example of code that is difficult to test: we have no easy way to control or verify the behaviour of the ClassB-instance used during the test. We normally avoid this problem by using the Inversion of Control principle (wikipedia.com). Whether this is applicable in this situation I cannot say. For this, I would have to see more of the code, and it would most probably be out of scope for StackOverflow.
As a quick and dirty fix, we can mock the call to classA.getSomeStuff() after we have created our mock:
#Spy private ClassA classA;
#Mock private ClassC classC;
...
#Test
void test1() {
ClassB classB = spy(classA.getSomeStuff());
when(classB.getResults()).thenReturn(classC);
when(classA.getSomeStuff()).thenReturn(classB);
classA.start();
}
As an aside: When using mockito, we should prefer the form
when(someMock.someMethod()).thenReturn(someResult);
over
doReturn(someResult).when(someMock).someMethod();
The former guarantees type safety at compile time, the latter does not. It is not always possible to use the former form (e.g. for methods returning void we have to use the latter form).
For one of my use case, I have to mock an autowired dependency only a single test case, while I want other tests to use the original one.
public class A {
#Autowired
private B b;
}
Class TestA {
#Autowired
private A a;
void test1() {
//using B without mock.
}
void test2() {
// mock B b in A here
}
}
I want to mock the private class variable 'b' here in some particular tests. I know if I have to mock B in entire class I can use #Mock, #InjectMocks and MockitoAnnotations.initMocks(), but that will mock 'b' for the other test cases as well where I want original behavior.
You can simply create a mock object, and temporarily assign it to variable b. Something like
public void test1() {
//normal test
}
while in the other:
public void test2() {
try {
B autowiredObject = b; //saving the original reference
b = mock(B.class);
when(b.someGetFunction()).thenReturn("it is mocked");
//rest of your test
} finally {
b = autowiredObject;
}
}
Please note the finally clause. It is there to ensure that the class state (autowired dependency) gets restored during your test. This is a very important practice, otherwise a fail in your test could theorertically affect your other tests in the same class, which is something you should always avoid.
Usually, you don't use Spring for unit-testing but rely on mocking dependencies and inject them manually into the test-object. A simple test method therefore can look like this:
#Test
public void testSomethingWithA() throws Exception {
// Arrange
A sut = new A();
B mockedB = mock(B.class);
// inject B into A
Whitebox.setInternalState(sut, "b", mockedB);
// Act
Object retVal = sut.doSomething();
// Assert
assertThat(retVal, is(equalTo(someExpectedValue)));
}
If you want to inject a real object into A instead of a mocked object (for whatever reason) simply switch mockedB in Whitebox.setInternalState(...) with your real object.
I've class method like below which creates a local object and calls a method on that local object.
public class MyClass {
public someReturn myMethod(){
MyOtherClass otherClassObject = new MyOtherClass();
boolean retBool = otherClassObject.otherClassMethod();
if(retBool){
// do something
}
}
}
public class MyClassTest {
#Test
public testMyMethod(){
MyClass myClassObj = new MyClass();
myClassObj.myMethod();
// please get me here..
}
}
When I'm testing myMethod, I want to mock otherClassObject.otherClassMethod to return something of my choice. otherClassMethod does some class to Message Queues and I don't want that in Unit test. So I want to return true when I do otherClassObj.otherClassMethod(). I know I must have used a factory for MyOtherClass instantiation in this case but it's legacy code and I don't want to change any code now. I see that Mockito doesn't provide this facility to mock MyOtherClass in this case but possible with PowerMockito. However, I could not find an example for above scenario but found only for static class. How should I mock local object inside a method of SUT ?
I also referred to some other OS questions like - Mocking methods of local scope objects with Mockito but they were not helpful.
A code example will be of great help.
If you are using PowerMockito you can use the whenNew method
It should look something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class) //tells powerMock we will modify MyClass to intercept calls to new somewhere inside it
public class MyClassTest{
#Test
public void test(){
MyOtherClass myMock = createMock(MyOtherClass.class);
//this will intercept calls to "new MyOtherClass()" in MyClass
whenNew( MyOtherClass.class).withNoArguments().thenReturn( myMock) );
... rest of test goes here
}
Also this other SO post has example code too PowerMockito Mocking whenNew Not taking affect
OK, this is not a real answer but with PowerMockito you can do this:
final MyOtherClass myOtherClass = mock(MyOtherClass.class);
// mock the results of myOtherClass.otherClassMethod();
PowerMockito.whenNew(MyOtherClass.class).withNoArguments()
.thenReturn(myOtherClass);
// continue with your mock here
Now, not sure whether you actually need the result of this otherClassMethod here, but if you don't, I'd suggest you mock the results of myMethod() instead -- unless myMethod() is what you want to test because this other method has an influence on it, and yes, in this case a refactoring should be considered... And not delayed ad vitam aeternam...
I was wondering whether there's a way to mock the field which is being autowired.
Consider the following case.
I have a class name A
public class A {
#Autowired
private B b;
public void aMethod() {
b.method();
}
}
The other class B looks like this
public class B {
public void method() {
// some code
}
}
Now i want to write junit for the method.
I know there's a way to mock the autowired field like this.
public class TestA {
#InjectMock
private A a;
#Mock
private B b;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
public void testAMethod() {
// write test case.
}
}
But my question is -> Is there a way to mock the autowired field inside method after creating object with new.
eg
public class TestA {
public void testAMethod() {
A a =new A();
// how to mock the B instance in it.
}
}
Please suggest or there's no way to do this????
I dont want to change from private modifier. Nor i want to add getter's and setters or reflection. I just want to know is there a way to mock the B instance after creating the new object of A class.
How about ReflectionTestUtils?
A a = new A();
B b = mock(B.class);
ReflectionTestUtils.setField(a, "b", b);
It's still reflection-based and has all related drawbacks, though it's quite simple and easy to read.
You can not do that with mockito, this would require to modify the bytecode of the class being tested. However Powermock allows such stubs. Note though that I and the creator of Powermock - Johan Haleby - would push for a refactoring instead of using Powermock. Powermock is very powerful, maybe too much, and working allows anyone to write legacy code, that would be difficultly maintainable or extensible (property you can find in poorly designed legacy code).
In your case I don't know what's wrong in your case with the dependency injection. However if the code need a new instance of B, it may be useful to have inject in A a factory/provider/builder class which will make a new instance of B. Such code can be easily stubbed with Mockito.
Whenever I want to test a class which uses resource injection I end up including a constructor that will only be used within the test:
public class A {
#EJB
B b;
// Used in tests to inject EJB mock
protected A(B b) {
this.b = b;
}
public A() {}
// Method that I wish to test
public void foo() {
b.bar();
}
}
Is there another way of mocking resource injection or this is the correct pattern to follow?
you could use easy gloss to that effect, it mocks the EJBs injection system.
another way is to set the field using reflexion in your tests, I sometime use something like this :
public static void setPrivateField(Class<? extends Object> instanceFieldClass, Object instance, String fieldName, Object fieldValue) throws Exception {
Field setId = instanceFieldClass.getDeclaredField(fieldName);
setId.setAccessible(true);
setId.set(instance, fieldValue);
}
Eliocs,
If type B where an interface then you wouldn't "just" bo doing it for test-cases; you'd be allowing for any alternative implementations of "B's behaviour", even if the need for it/them hasn't been dreamed-up yet.
Yeah, basically that's the only pattern to follow (AFAIK)... so (rightly or wrongly) you may as well make the best of it ;-)
Cheers. Keith.
It's certainly one way to do it, although I'd rely on package access; don't provide a constructor injection point, but simply have your test in the same package as the bean being tested. That way, your test can just access the value directly (assuming it's not private):
#Test
public void EJBInjectionTest() {
A a=new A();
a.b=new B() {
// mock functionality here, of course...
};
assertNotNull(a.b);
}
According to this article (Mockito and Dependency Injection), Mockito has support for injecting mocked resources.
public class ATest
{
#InjectMocks
private A a; //this is your class under test into which the mocks will be injected.
#Mock
private B b; //this is the EJB to be injected.
#Before
public void setUp()
{
MockitoAnnotations.initMocks(this);
}
}
You can also inject multiple mocks. Just declare them in the same way as we did for B b.
The initMocks part can also be done in each test or in a BeforeClass setup method depending on your needs.