Reputation: 1297
I am using mockito to write some unit tests for an application which is already tested with integration testing but we need also to develop unit tests.
This is the code for the testing :
public class TestResourceB {
@Mock
ResourceB b;
@Mock
ResourceC c;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
TestObjects.InitializeObjects();
}
@Test
public void testMethodResourceA() {
when(b.callFuncA()).thenCallRealMethod();
when(b.callFuncB()).thenReturn(TestObjects.mockedListA);
when(b.callFuncC((B)anyVararg())).thenCallRealMethod();
when(c.callFuncB()).thenReturn(TestObjects.mockedListB);
when(c.callFuncA()).thenCallRealMethod
String output = b.callFuncA();
}
}
This is the class ResourceB
public class ResourceB {
ResourceC c = new ResourceC();
public String callFuncA(){
/*Calling callFuncB and doing some other stuff*/
String test = callFuncC(arg1);
}
public List<A> callFuncB() {
/*returns the mocked list A*/
}
public String callFuncC(B arg1) {
String test2 = c.callFuncA(); // It crashes here
/*doing some other stuff*/
}
}
This is the class ResourceC
public class ResourceC {
public String callFuncA() {
/*Calling callFuncB and doing some other stuff*/
return testString;
}
public List<B> callFuncB() {
/*return a List*/
}
}
The problem that I have is that in method callFuncC in class ResourceB when the line
String test2 = c.callFuncA();
is called I get a NullPointerException
Any idea why this could be happening ?
Upvotes: 1
Views: 17866
Reputation: 42283
There is several issues in your code, the first one being that you are mocking the class you want to test, doing that you will only test the mock of ResourceB
or you'll have to stub the code and force chosen method to call real code (thenCallRealMethod
). The main idea is to never mock the class you are testing.
That is also why you have an NPE, because a mock don't need internal fields instance. As it should'nt need to.
Here's a correct way, there might be variations but that one is the most straightforward. So basically you'd want to test the interactions between ResourceB
and ResourceC
, as this is a unit test of ResourceB
you'd want to mock ResourceC
. The thing is mocks are per instance so you have to pass the mocked one to ResourceB
.
It can be injected via constructor injection, you then need to modify the ResourceB
:
public class ResourceB {
ResourceC c;
public ResourceB() { c = new resourceC(); } // normal behavior
@VisibleForTesting // guava annotation (in, order to expalain why there is this constructor)
ResourceB(ResourceC c_override) { c = c_override; } // constructor for the test, note the package visibility
// ...
}
And in the test you'll write it this way :
public class TestResourceB {
ResourceB tested_b;
@Mock ResourceC mocked_c;
@Before
public void init_tested_and_mocks() {
MockitoAnnotations.initMocks(this);
tested_b = new ResourceB(mocked_)
}
@Test
public void ensure_result_from_ResourceC_is_returned() {
// given
when(mocked_c.callFuncA()).thenReturn("result that should be returned");
// when
String output = tested_b.callFuncA();
// then
assertThat(output).isEqualTo("result that should be returned");
}
}
By the way here's a few things to add :
Upvotes: 6