I have 3 classes as shown below and I want to write a Unit test for validate() of Class A. I do not want to mock Class B. I want to mock Class C and always return same string when getDetails() is called. Is it possible with Mockito? If not, is there any alternative?
Class A{
void validate(){
B b = new B();
b.verify();
}
}
Class B throws Exception{
void verify(){
C c = new C();
c.getDetails();
}
}
Class C{
String getDetails(){
//Does an API call and returns the part of response as a string
}
}
CodePudding user response:
You can use PowerMock for this. See the following example:
@RunWith(PowerMockRunner.class)
@PrepareForTest(C.class)
public class Test {
@Test
public void testMockingC() throws Exception {
PowerMockito.stub(PowerMockito.method(C.class, "getDetails")).toReturn("Mocked successfully!");
A a = new A();
a.validate();
}
}
Since no method returns the relevant value I couldn't do some assertion, but you can put a breakpont and track the program flow while running this test, c.getDetails()
will return Mocked successfully!
.
CodePudding user response:
B
doesn't seem to let you pass in a C
, so it's hard to substitute the C
used with a test double. The problem is that B
knows all the details of C
's construction even when it doesn't (and shouldn't) care. Dependency injection is an important pattern: something like
interface DetailsProvider {
public String getDetails();
}
class B {
public B(DetailsProvider detailsProvider) {
this.detailsProvider = detailsProvider;
}
private DetailsProvider detailsProvider;
}
and then
class FakeDetailsProvider implements DetailsProvider {
@Override
String getDetails() {
return "foo";
}
}
so that in the test you can write
B someB = new B(new FakeDetailsProvider());
and in the production code, of course
class C implements DetailsProvider {
...
}
I've introduced the interface as abstraction - so that clients using it only know what operations (i.e. getDetails
) they can perform, without being tied to any concrete implementation.
Note that this may not compile; I've not written Java for a while now!