2

I have a service class which is responsible for instantiating repositories and using them. It makes an external Http request which ideally I would like to mock for testing. However, I am not quite sure the best way to do this.

For example, right now the class looks like this:

public function lookUp($identifier)
{
    $client = new Curl();
    $data = $this->provider->lookUp($identifier, $client);

    // do stuff w the response
}

It is not possible to mock the Http response since it is contained within the method.

An alternative might be to do something like this:

public function lookUp($identifier, $client = null)
{
    if ($client === null) {
        $client = new Curl();
    }

    $data = $this->provider->lookUp($identifier, $client);

    // do stuff w the response
}

and then I could have a $client for mocking in my test. However, this would mean changing (and messying) my code just for the purpose of the test.

Should I do this? Is there a better way to test this?

amon
  • 134,135
tam5
  • 165

1 Answers1

12

It's a matter of perspective. Writing tests for our code forces us to decouple the code. You COULD view this as "code that exists only for the tests", but I think this is misleading.

What you're actually doing is decoupling your code. You are removing hard dependencies and getting rid of the headaches that come with code that news up everything it needs. These are desirable goals in their own right. It ALSO has the effect that the code becomes more testable, so you can look at it either way.

For code to be testable, it has to be "good" (used in a very sloppy way, I am aware that any discipline can be misused to produce a mess). For code to be "good", it has to be testable (at least in large parts).

You can take your pick what you like best: having automatic regression tests, or having a design that is easier to modify and/or refactor later on.

sara
  • 2,559
  • Nice, but I'd remove the tautological third paragraph :) – Jeffrey Sweeney Apr 12 '16 at 15:49
  • To add to your answer, adhering to dependency injection in business logic rather than having hard coded dependencies also creates trustworthy interfaces. If you adhere to DI, you can be pretty sure unless you pass a class a database, it will never access it (and vice versa, if you are required to pass it, you better make sure to know what you're doing, because you might be modifying real data). – Andy Apr 12 '16 at 15:58
  • 1
    yes, I fully agree, one of the things I've come to value most over the years (especially after dabbling a bit in haskell which has a VERY strong type system) is APIs that don't lie. hidden dependencies really are hell, and they make code so much harder to get a feel for. – sara Apr 12 '16 at 16:05