Doctrine Repository Hydration, Part 2: Unit Tests

Last time, in the Doctrine ORM Repository Hydration
article, we discussed how to use the Doctrine ORM to separate our SQL code
into a repository layer. This enabled us to pass a strongly typed DTO to the
UI layer as opposed to stringly-typed arrays.

This article will be focused on designing phpunit tests for the previous
article. We will focus our efforts on these four repository implementations:

Since we know that each of the four classes implements the
CompanyRepositoryInterface, we can write our tests while targeting this
interface. Code against an interface; test against an interface.
This will allow us to keep our tests DRY.

The AbstractDoctrineCompanyRepositoryTest class defines a single abstract
method to get the specific repository implementation we want to test. The
abstract method, getCompanyRepository(), uses the new PHP 7 strict
return type declarations to ensure that we are testing against a class
that conforms to the CompanyRepositoryInterface.

The most basic test that we can write involves an empty database with zero
companies and employees. When calling getCompanyStats() we expect there to
be zero active and zero inactive employees.

The next meaningful test that we can write involves adding records to the
database for a single company containing three employees, two of which are
active. We split the body of the unit test method into three blocks using
the Arrange – Act – Assert (AAA) strategy that Kent Beck describes in his
Test-Driven Development book. This is also referred to
Given – When – Then in some circles.

Above, the Assemble block is delegated to a separate private method,
getCompanyIdForStatsTest(), which initializes the database with the
conditions defined earlier (2 active, and 1 inactive employee). The Act
block simply calls getCompanyStats(), and the Assert section contains
two assertions for the employee totals. This concept will help organize your
tests into simple meaningful units.

Below you can see the code that will setup a single Company containing 3
employees. It delegates the creation of the Entity object via a getDummyXX()
method. This strategy will help decouple your tests from the creation of
entities. An indicator of coupled test code is the use of the new keyword
to create Entities in your tests.

We leverage $this->entityManager to store these new Entities to the
database with persist, flush, and clear. Clearing the EntityManager is
recommended after assembling your unit test. This will detach any Entities
that it currently manages. It will also clear the Identity Map, which will
keep any future repository method calls in the Act block from being tainted
by this first-level-cache. Doctrine uses the Identity Map pattern (for
optimization) to keep a reference to Entities when you fetch them from the
database.

Summary

We covered a few best practices that are helpful in my projects.
Testing against an interface can save you time and allow you to focus
on the interface requirements. Arrange – Act – Assert keeps your unit
test methods clean and consistent. Clearing the EntityManager avoids
side-effects in your repository layer tests.