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?

  • 2
    TDD has a long-standing tradition of forcing software developers to write their code in ways that make it easier to test. – Robert Harvey Apr 12 '16 at 15:29
  • kind of a chicken/egg thing there, it's not so much that TDD forces you to write testable code. if you write test-first, your code is tested before it even exists. you are never "forced" by anyone to modify your code to become more testable, the code you write is testable per definition. – sara Apr 12 '16 at 15:36
  • possible duplicate of Is it a bad practice to modify code strictly for testing purposes – gnat Apr 12 '16 at 15:37
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.

  • 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.