2

I have given myself a challenge to making use of testing my code as I develop it as I figured this is not only a good practice especially for a back end developer but also helps one a lot in building a scalable and extendable code in the long run.

I have a class that defines an array of supported doctrine drivers. Inside this class there is a method that creates an instance of any annotation driver that is supported by my bundle.

protected $supportedAnnotationDrivers = array(
  'Doctrine\ORM\Mapping\Driver\XmlDriver',
  'Doctrine\ORM\Mapping\Driver\YamlDriver',
  'Doctrine\ORM\Mapping\Driver\AnnotationDriver'
 );

The method that creates any instance of these drivers can be seen below:

 public function getAnnotationDriver($classDriver, $entityDriver)
 {
     if(!in_array($classDriver, $this->supportedAnnotationDrivers)){
        throw new \RuntimeException(sprintf(
           "%s is not a supported Annotation Driver.", $classDriver
          ));           
        }

      if('Doctrine\ORM\Mapping\Driver\AnnotationDriver' === $classDriver){
           $annotationDriver = new $classDriver(new AnnotationReader(), array($entityDriver));
           AnnotationRegistry::registerLoader('class_exists');
         }else{
          $annotationDriver = new $classDriver($entityDriver);
       }

      return $annotationDriver; 
     }

Before I go any further I have to say I have consulted PHPUnit Manual and StackOverflow, here; here; here and there , for some insights but I am getting confused all the time. and none of these links are providing me with certainty that I am going about this the right way.

Below is my test function inside my test class:

public function testUnsupportedAnnotationDriverException()
{
     try{

        $entityManagerService = new EntityManagerService();

         //Client requests a unsupported driver
         $unsupportedDriver              = 'Doctrine\ORM\Mapping\Driver\StaticPHPDriver';
         $actualUnsupportedException     = $entityManagerService->getAnnotationDriver(
         $unsupportedDriver, __DIR__ . '/../../Helper'
       );
      }catch(\RuntimeException $actualUnsupportedException){
        return;
     }

    $this->fail('An expected exception has not been raised!.');
  }

I am really confused when it comes to this part. In my test I am using an exception that is raised by my code which is RuntimeException and my test passes. When I change client code to throw just Exception but leave my test as is it fails and throws the exception from client code. I am happy to know that my test fails because the exception thrown in my test gives me what I would hope to get when a user passes an unsupported driver.

However, I am lacking contextualization herein of the annotation usage and the $this->fail("text/for/failer/) function when testing exceptions.

How best could I go about writing a test for this method? Is what I have done exactly how the test should behave perhaps its me not having grasp the concept behind this part of PHPUnit? Below is an output I get from PHPUnit:

Case 1:Exceptions are the same from test and client code

Luyanda.Siko@ZACT-PC301 MINGW64 /d/web/doctrine-bundle
$ vendor/bin/phpunit
  PHPUnit 3.7.38 by Sebastian Bergmann.

   Configuration read from D:\web\doctrine-bundle\phpunit.xml

   ......

   Time: 1.49 seconds, Memory: 3.00Mb

  OK (6 tests, 9 assertions)

 Luyanda.Siko@ZACT-PC301 MINGW64 /d/web/doctrine-bundle

Case 2:Exceptions are not the same from test and client code

Luyanda.Siko@ZACT-PC301 MINGW64 /d/web/doctrine-bundle
 $ vendor/bin/phpunit
   PHPUnit 3.7.38 by Sebastian Bergmann.

   Configuration read from D:\web\doctrine-bundle\phpunit.xml

   ..E...

   Time: 1.59 seconds, Memory: 3.00Mb

   There was 1 error:

 1)   PhpUnitBundle\Unit\ApplicationContext\Service\EntityManagerServiceTest::testUnsupportedAnnotationDriverException

Exception: Doctrine\ORM\Mapping\Driver\StaticPHPDriver is not a supported Annotation Driver.

 D:\web\doctrine-bundle\lib\DoctrineBundle\ApplicationContext\Service\EntityManagerService.php:33
 D:\web\doctrine-bundle\lib\PhpUnitBundle\Unit\ApplicationContext\Service\EntityManagerServiceTest.php:68

 FAILURES!
 Tests: 6, Assertions: 9, Errors: 1.

I really want to know the best way to know what I am doing here and if I am doing it right - if not the best way to do it. Perpahs what I am trying to do is not even worthe it but I believe no single line of code should be seen as worthless and unworthy of testing.

1 Answer 1

2

In general, code that you provided is valid and work as it should. You describe what you expects from code and then test that your code meet your expectations.

In your case you are expecting that exception with type \RuntimeException will be thrown and if it is just \Exception - there is an error

Another question is how phpunit tell about it to you. In your case it shows message

1)   PhpUnitBundle\Unit\ApplicationContext\Service\EntityManagerServiceTest::testUnsupportedAnnotationDriverException
Exception: Doctrine\ORM\Mapping\Driver\StaticPHPDriver is not a supported Annotation Driver.

It is not very obviouse. You can make expectations more explicit if descibe them with setExpectedException:

/**
 * Test fail if client requests a unsupported driver
 */
public function testUnsupportedAnnotationDriverException()
{
    $entityManagerService = new EntityManagerService();

    $this->setExpectedException(\RuntimeException::class);
    // $this->setExpectedException('RuntimeException'); // for PHP < 5.5

    $unsupportedDriver = 'Doctrine\ORM\Mapping\Driver\StaticPHPDriver';
    $actualUnsupportedException = $entityManagerService->getAnnotationDriver(
        $unsupportedDriver, __DIR__ . '/../../Helper'
    );
}

or using proper annotation @expectedException:

/**
 * Test fail if client requests a unsupported driver
 *
 * @expectedException \RuntimeException
 */
public function testUnsupportedAnnotationDriverException()
{
    $entityManagerService = new EntityManagerService();

    $unsupportedDriver = 'Doctrine\ORM\Mapping\Driver\StaticPHPDriver';
    $actualUnsupportedException = $entityManagerService->getAnnotationDriver(
        $unsupportedDriver, __DIR__ . '/../../Helper'
    );
}

Now if you change throw \RuntimeException to throw \Exception in tested method, you can note that phpunit's message now look like this

Failed asserting that exception of type "Exception" matches expected exception "\RuntimeException". Message was: "Doctrine\ORM\Mapping\Driver\StaticPHPDriver is not a supported Annotation Driver." 

So you see more explicit what is wrong

1
  • Thanks @SmoothAF. I will give this a try again and come back to accept your answer should I be satisfied. Thanks again for your time. Commented Jan 22, 2016 at 7:52

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