5

I am writing a unit test upfront for a service that does not exist yet. Let's just say it is called ResponseFormatter.

I want to start adding unit tests for what I expect this service to do. How do I inject it to a UnitTestCase, or reference it?

Example, I am trying to do something like:

class FormatterTest extends UnitTestCase {

  /**
   * @dataProvider responses
   */
  public function testThisWorks($response, $expected) {
    // the following line I want to call a service, 
    // ex. like $this->responseFormatter->format($string);
    $clean = html_entity_decode(strip_tags($response));
    $this->assertEquals($expected, $clean);
  }

  public function responses() {
    return [
      ['not-set', 'not-set'],
      ['<strong>foo</strong>', 'foo'],
      ['&amp; #93 bar', '& #93 bar'],
    ];
  }
}
8

If your new service is sufficiently independent (it doesn't have any or many of it own dependencies), then just create it the setUp(). And then if you have dependencies, you set up mocks (also called doubles).

An example of a this in core is TimeTest::setUp() does:

protected function setUp() {
  parent::setUp();

  $this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
  $this->time = new Time($this->requestStack);
}

A mocked request stack is created, and the setup then directly instantiates the service class being tested (Time() in this case), passing in the mocked dependency to the constructor.

Then assertions in test methods are pretty simple

public function testGetRequestTime() {
  $expected = 12345678;

  $request = Request::createFromGlobals();
  $request->server->set('REQUEST_TIME', $expected);

  // Mocks a the request stack getting the current request.
  $this->requestStack->expects($this->any())
    ->method('getCurrentRequest')
    ->willReturn($request);

  $this->assertEquals($expected, $this->time->getRequestTime());
}

The mock simulates what the service's dependency would do, and then the service method is invoked directly.

If your service has a lot of dependencies, or mocking them is hard, then you should do a KernelTest instead of a TestCase or UnitTest. However, that may be an indication that your service is too complicated and needs to be broken up (I am also having a problem thinking of a core service that is kernel tested and not unit tested).

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.