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.
The idea is to first introduce an abstraction, of which you can have different implementations:
interface DetailsProvider {
public String getDetails();
}
There will be one implementation that makes the real API call, used in the production code and another that's completely in your control, for the tests.
Then, you make B
take a DetailsProvider
as a constructor parameter. The beauty in this is that it now no longer knows how the instance is created, making it easy to supply different versions of it. Anything implementing the interface will do.
class B {
public B(DetailsProvider detailsProvider) {
this.detailsProvider = detailsProvider;
}
public void verify () {
String details = detailsProvider.getDetails();
...
}
private DetailsProvider detailsProvider;
}
For testing, we can have a fake:
class FakeDetailsProvider implements DetailsProvider {
@Override
String getDetails() {
return "foo";
}
}
so somewhere in your test setup, you have, e.g.
B someB = new B(new FakeDetailsProvider());
In the production code, C
now needs to implement the interface:
class C implements DetailsProvider {
@Override
public String getDetails() {
// Make the real API call.
}
}
and again, you just wire the two up:
B myB = new B(new C());
Note that this may not compile; I've not written Java for a while now!