2

Normally with Drupal 8 I can use dependency injection like this:

<?php class ExampleController extends ControllerBase { private $http_client; public function __construct(HttpClient $http_client) { $this->http_client = $http_client; } public function create(ContainerInterface $container) { $http_client = $container->get('http_client'); } public function getResource() { $response = $this->http_client->get('http://biebertunes.com?q=selena'); return $response->getBody(); } } 

I can then use the $http_client property's methods.

Now in my testing class I'm already extending the UnitTestCase class, so I don't have access to the create method for dependency injection.

<?php class ExampleTest extends UnitTestCase { public function testGetResource() { $mock = $this->getMock('\Drupal\Example\ExampleController'); } } 

Now when I run my unit tests it complains that I don't have the $http_client parameter. So how can I inject $http_client into the unit test without the create method?

1 Answer 1

4

I have few thoughts about this situation:

  1. Controllers should not contain business logic, services should. Therefor unit testing a controller is not a good idea in the first place.
  2. If you are unit testing your controllers "getResource" method, why do mock the controller itself? You should mock the HttpClient. (that's the strong part of DI)
  3. First you mock the classes which your constructor needs as arguments. Then you just create your object, which will you test like this: $example_controller = new ExampleController($http_client_mock); And that's it.
6
  • 1
    You're right, of course, about the whole business-logic-in-a-controller - but to be fair, which part of the OP's code would you rather see in a service? Surely creating a new service simply to wrap around the one-line call to the other service (http_client) would be massive overkill here, wouldn't it? I mean, how far does that go? Does the new service need another service to wrap it in another context? Personally I think this is where best practice and the usual advice gets a bit murky. Good answer though Commented Jul 21, 2016 at 12:01
  • 1
    I agree with you! As you said he has only a one-line wrap.. so why do you wan't to test it in the first place? This method is much more like a facade here, and does nothing on it's own. Commented Jul 21, 2016 at 12:04
  • 1
    Actually yeah, you're totally right :) The OP should be satisfied that the HTTP client service works by using its tests, rather than essentially adding their own version of it. If they want to make sure the end-to-end works, an acceptance test would probably be more appropriate Commented Jul 21, 2016 at 12:17
  • Hey there. Agreed about there being no point in testing that method but it was just there as more of an example. Your answer helped me get on the right track. I also had to use an additional step of implementing the setUp() method and adding the mock objects to the service container via \Drupal::setContainer(). Then I was able to pass the mock objects into my class that I'm testing. Thanks! Commented Jul 22, 2016 at 6:27
  • It will help future people's of you post a full answer with code answering the question as you posed it Commented Jul 22, 2016 at 10:15

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.