Reputation: 309
I am very new to Test Driven Development and cannot figure out how to write effective tests for a class I wrote. The class is as follows (Java):
public class MyServiceClassImpl implements MyService {
private someExternalClient client;
private anotherExternalClient anotherClient;
public MyServiceClassImpl() {
client = someExternalClient.getInstance();
anotherClient = anotherExternalClient(client);
}
public String methodWhichDoesSomething(String query) {
return anotherClient.getResponse(query);
}
}
For the test, I try a few queries and compare the response I get with the response I expect (I expect it because I know what anotherClient will return). It works alright but this is technically an integration test since I am calling an external dependency. I do not understand how to write "unit" tests in this case. More specifically, I don't know how to mock the dependencies since the fields are private, there are no setters and the constructor doesn't take any parameters. How would I "supply" the instance of the class with my mocks even if I created them? I wrote the class myself too so please let me know if I should re-design the class, maybe provide getters and setters?
Upvotes: 3
Views: 5571
Reputation: 6992
This is a very common situation that most developers falls into. The questions how to make the code testable. Rule of thumb "If you don't have any security concerns, do not afraid to change design so your routines are testable." This is actually a very good thing, because you SUT (System Under Test) API is appealing to its clients and easier to make changes and extend.
In you case leave your Integration Test as it is because it tests the whole system with database interaction/config etc.
Generally what is important is the Unit Test. But looking at you code the method
methodWhichDoesSomething(String query)
hardly has any behavior at all. It only calls another client to return a response. So you need to decide whether you need really write a Unit Test for this. I would not recommend as it does not have any behavior to Unit Test.
But if you really want to Unit Test, whether the GetResponse(..) method has been called with expected parameter type is a candidate.
In order to that Inject your dependency AnotherExternalClient into you SUT (System Under Test).
public MyServiceClassImpl(AnotherExternalClient externalClient)
{
In you test setup a mock on AnotherExternalClient and verify whether the method has been invoked. Use this constructor injection if your parameter is a mandatory type to your MyServiceClassImpl. If not simply use the property injection if the injection is an optional.
UPDATE
Reg. "Inject your dependency"
The instance you returning from anotherExternalClient(clent);, which is type of anotherExternalClient can be injected into your SUT (System Under Test) MyServiceClassImpl. The way you inject is either with a property or via constructor. I will explains this a bit later. You don't have to worry about writing code like client = someExternalClient.getInstance();
as this can be externalized and return the client which then used to return the anotherExternalClient. In otherwords your SUT (System Under Test) MyServiceClassImpl should only care about anotherExternalClient not someExternalClient. Having less dependency like this simplifies your design and make it easier to Unit test.
Reg. "Property Injection vs Ctro Injection" I would not repeat my self, here is another SO question has some information on this.
Hope this helps.
This is critical because when it comes to Unit testing you can easily provide you with the mock/fake implementation for testing.
Upvotes: 5