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.
Related
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.
I have a load method and a save method in a DAO and a domain class. In my application I load a domain object, update attribute values and save the object again. I wrote this test for the app:
import ...
#RunWith(MockitoJUnitRunner.class)
public class MyAppTest
{
#Mock
private MyDao myDao;
#InjectMocks
private MyApp myApp;
#Test
public void testMyMethod(){
// given
MyDomainClass myObj = new MyDomainClass();
when(myDao.load(anyInt())).thenReturn(myObj);
// when
myApp.myMethod();
// then
ArgumentCaptor<MyDomainClass> argumentCaptor = ArgumentCaptor.forClass(MyDomainClass.class);
verify(myDao).save(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().myInt, is(1));
}
}
The test passes although the logic contains a bug:
public class MyApp
{
private MyDao myDao = new MyDao();
public void myMethod(){
MyDomainClass myObj = myDao.load(0);
myDao.save(myObj);
System.out.println("Saved myObj with myInt=" + myObj.myInt); // myInt=0
myObj.myInt = 1;
}
}
My question is if anyone else experienced this, and what (junit) test strategy would expose the bug.
EDIT: In response to the first suggested solution, I replaced the argument captor like so:
...
#Test
public void testMyMethod(){
...
MyDomainClass expected = new MyDomainClass();
expected.myInt = 1;
verify(myDao).save(eq(expected));
}
and the test still passes. The reason is the same: by the time verify is invoked, the value of myInt is 1 in both instances. I'm trying to verify that save was invoked with myInt of myObj set to 0, i.e. this test should fail.
My question was also if there is a general thing, e.g. a different test strategy that I should consider. Are ArgumentCaptors a bad choice in some cases? I know I could write an integration test instead, but imo this should be testable in a unit test.
By the time this is invoked ...
assertThat(argumentCaptor.getValue().myInt, is(1));
... the value of myInt is 1 since it is set to that value inside myApp.myMethod(); which is invoked before the verification.
Using an Answer
If you want to assert against the state of MyDomainClass as it was when myDao.save() was invoked then you'll need to capture that state via an answer in the 'when' stage.
Since Mockito records a reference to the MyDomainClass instance passed to myDao.save() (rather than a copy of it) you could use an Answer to record your own copy and then assert against that copy.
For example:
#Test
public void testMyMethod(){
// given
MyDomainClass myObj = new MyDomainClass();
when(myDao.load(anyInt())).thenReturn(myObj);
AtomicReference<MyDomainClass> actualSavedInstance = new AtomicReference<>();
doAnswer(invocation -> {
MyDomainClass supplied = (MyDomainClass) invocation.getArguments()[0];
// copy/clone state from supplied - which represents the instance passed to save - into a separate
// instance which can be used for an assertion
MyDomainClass actual = new MyDomainClass();
actual.myInt = supplied.myInt;
actualSavedInstance.set(actual);
return null;
}).when(myDao).save(myObj);
// when
myApp.myMethod();
assertThat(actualSavedInstance.get().myInt, is(0));
}
An Alternative
An alternative to this might be to delegate the 'post update increment' within MyDao.save() to a separate actor and then mock that actor and verify it.
For example, change MyApp as follows:
public void myMethod(){
MyDomainClass myObj = myDao.load(0);
myDao.save(myObj);
System.out.println("Saved myObj with myInt=" + myObj.myInt); // myInt=0
// the handler will do this: myObj.myInt = 1;
postSaveHandler.handle(myObj);
}
And then implement the test like so:
#RunWith(MockitoJUnitRunner.class)
public class MyAppTest
{
#Mock
private MyDao myDao;
#Mock
private PostSaveHandler postSaveHandler;
#InjectMocks
private MyApp myApp;
#Test
public void testMyMethod(){
// given
MyDomainClass myObj = new MyDomainClass();
when(myDao.load(anyInt())).thenReturn(myObj);
// when
myApp.myMethod();
ArgumentCaptor<MyDomainClass> argumentCaptor = ArgumentCaptor.forClass(MyDomainClass.class);
verify(myDao).save(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().myInt, is(0));
verify(postSaveHandler).handle(myObj);
}
}
I am writing unit test for methods to find banks near my location.
I mocked the class and tried to call the methods.
But, control is not going to method to execute it.
Below is unit test case.
#Test
public void testFindBanksByGeo() {
String spatialLocation = "45.36134,14.84400";
String Address = "Test Address";
String spatialLocation2 = "18.04706,38.78501";
// 'SearchClass' is class where 'target' method resides
SearchClass searchClass = Mockito.mock(SearchClass.class);
BankEntity bank = Mockito.mock(BankEntity.class);
// 'findAddressFromGeoLocation' and 'getGeo_location' to be mocked. They are called within 'target' method
when(searchClass.findAddressFromGeoLocation(anyString())).thenReturn(Address);
when(bank.getGeo_location()).thenReturn(spatialLocation2);
// 'writeResultInJson' is void method. so needed to 'spy' 'SearchClass'
SearchClass spy = Mockito.spy(SearchClass.class);
Mockito.doNothing().when(spy).writeResultInJson(anyObject(), anyString());
//This is test target method called. **Issue is control is not going into this method**
SearchedBanksEntity searchBanksEntity = searchClass.findNearbyBanksByGeoLocation(spatialLocation, 500);
assertNull(searchBankEntity);
}
What i have tried is also calling the real method on it,
Mockito.when(searchClass.findNearbyBanksByGeoLocation(anyString(), anyDouble())).thenCallRealMethod();
This calls real method but the methods i mocked above, are executing like real one. Means 'mocked methods' are not returning what i asked them to return.
So, what wrong i am doing here ?
why method is not executing?
The method is not getting called because you are calling it on a mock. You should call the method on an actual object.
Or you could use something like this before invoking the method.
Mockito.when(searchClass.findNearbyBanksByGeoLocation(Mockito.eq(spatialLocation), Mockito.eq(500))).thenCallRealMethod();
But I think this is not the way you should write the test. You shouldn't be mocking SearchClass in the first place. Instead there would be a dependency in SearchClass which gets you the address and geo location. You should be mocking that particular dependency.
OK, let's say we have this code:
class Foo {
// has a setter
SomeThing someThing;
int bar(int a) {
return someThing.compute(a + 3);
}
}
We want to test Foo#bar(), but there's a dependency to SomeThing, we can then use a mock:
#RunWith(MockitoJunitRunner.class)
class FooTest {
#Mock // Same as "someThing = Mockito.mock(SomeThing.class)"
private SomeThing someThing,
private final Foo foo;
#Before
public void setup() throws Exception {
foo = new Foo(); // our instance of Foo we will be testing
foo.setSomeThing(someThing); // we "inject" our mocked SomeThing
}
#Test
public void testFoo() throws Exception {
when(someThing.compute(anyInt()).thenReturn(2); // we define some behavior
assertEquals(2, foo.bar(5)); // test assertion
verify(someThing).compute(7); // verify behavior.
}
}
Using a mock we are able to avoid using a real SomeThing.
Some reading:
http://www.vogella.com/tutorials/Mockito/article.html
https://github.com/mockito/mockito/wiki
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.
I have the following Java classes:
public class A
{
#Autowired
private B b;
public int aFn()
{
int something = b.bFn();
}
}
public class B
{
#Autowired
private C c;
public int bFn()
{
int something = c.cFn();
}
}
public class C
{
public int cFn()
{
return 231;
}
}
And the following test using Mockito to test the above code:
public class test
{
#Autowired
private A a;
private C c;
#Test
public void testA()
{
c = mock(C.class);
when(c.cFn(),anyInt()).thenReturn(something);
assertEquals(0, a.aFn());
}
}
When I debug testA, I find that real c.Cfn() gets executed, not the mocked one.
Is there anything what I am doing incorrectly here?
Please help!
First of all, you should always mock the direct dependencies of an object, and not its transitive dependencies. So you should mock B, and not C, to test A. Then you would write a unit test for B by mocking C.
Second: you're not injecting the mock anywhere in the unit test. What you should have is:
public class Test {
// not autowired here
private A a;
private B mockB;
#Test
public void testA() {
mockB = mock(B.class);
when(b.bFn(), anyInt()).thenReturn(something);
// the missing part: injecting the mock into the tested object
a = new A(mockB);
// or a = new A();
// a.setB(mockB);
assertEquals(0, a.aFn());
}
}
When you use mock(B.class), you get one mock instance of B. That doesn't mean that all the other instances of B will do what the mock does.
Mocking C to test A is a bad practice: unit tests should test one class in isolation of the others. But if you really want that, then create a mock C, create a B and inject the mock C inside it, then create an A and inject the B inside it.
A --> B --> mockC
Forget whether what you want to mock is direct or nested.
Think of it from Spring's philosophical point of view.
What you are essentially want to do is mock a bean.
In your case, you have to mock bean for Class c using #MockBean annotations.
#RunWith(SpringRunner.class)
public class Test {
...
#MockBean private C c;
...
}
Please refer this article for details.