Mocking legacy code is hard. Especially, if it’s a third-party library and you have little control over how it’s written. It is even more difficult to unit test a type that is instantiated internally. One can argue that it should be refactored to accept dependencies via constructor injection. However, constraints such as time, budget, experience with the offending code, or even access to the source often prevent paying down the technical debt accumulated in these legacy systems.
This post will show you how to mock an external library (concept) where it calls a login service class that cannot be sent via dependency injection
LoginService class validates user based on username and password:
This is instantiated and called by a class internally whenever user is validated:
This example is intentionally simplistic. The goal here is to show the way to mock such scenarios where it is out of the developer’s hands to refactor the code in such a way as to allow for wrapping the class with a proxy or even replacing it with an interface.
In JustMock it is possible to mock a member regardless of its instance. This is of course limited to the particular context defined by the developer of the test so as to not lead to side effects, and everything behaves as expected.
The mechanism for forward mock a dependency is by using the IgnoreInstance() method when arranging the behavior of the mock. This instructs the profiler to replace calls to that method on instances in the call chain with the mocked call.
In order to assert that ValidateUser method is called, I wrote the following specification:
This works great under most cases. However, if LoginService throws an exception inside its constructor (as in our example service implementation) or the constructor is executing code that is interfering with the test (such as open a database connection) then the above specification will fail.
The good news is that JustMock has you covered. Instead of creating a new instance of your service, you create a Mock of your concrete type and mark the constructor as mocked. This will then bypass and code in the constructor of the mocked type, and your test will work as expected.
My updated specification is shown in the next code listing:
This will make the test green as I have wanted.
Although sending instance via Dependency Injection is considered a much better way of handling dependencies (see this post by my coworker Phil Japikse on Why SOLID Matters), it is a simple fact that you will have to work with code that is not perfect and clean. In that regard JustMock can save your day and help you deliver more than expected.