Symfony Testing: using Repository pattern without connecting to database

In this article we are gonna write tests that are independent from database for symfony using the repository pattern.

I’ve written an article recently about how to use the repository pattern in a solid way which we are gonna follow in this article as well , here’s a tl;dr for the repository pattern the solid way in symfony article : create an interface for abstracting the repository and type-hint the abstraction instead of the implementation and make the repository implement the interface then symfony’s dependency injection would automatically provide us with the implementation using autowire.(you can read that article for more details)

here’s our controller form past :

here’s our repository interface:

use App\Entity\Post;interface PostRepositoryInterface {
public function findById(int $id):?Post;

and here’s our doctrine implementation of it (from last post):

namespace App\Repository;use App\Entity\Post;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
@extends ServiceEntityRepository<Post>
* @method Post|null find($id, $lockMode = null, $lockVersion = null)
class PostRepository extends ServiceEntityRepository implements PostRepositoryInterface
public function __construct(ManagerRegistry $registry)
parent::__construct($registry, Post::class);
public function findById(int $id): ?Post
return $this->find($id);

For testing our controller method we can either mock our repository or implement a fake repository, but the point of using repository pattern was to make us able to use multiple implementation in the first place, also there are a lot of articles on how using fakes is a better practice than using mocks as test doubles, here’s one , then lets go for that route.

here’s our fake implementation for testing purposes:

Now we have two implementations of the repository interface and we need to tell symfony’s dependency injection system how to provide us with each one of them. in php 8 and symfony 6 you can use the when attribute to achieve this. basically we’ll use #[When(env: ‘dev’)] and #[When(env: ‘prod’)] for development and production environments and #[When(env: ‘test’)] for the testing environment. here’s what our repositories look like after using it:

the doctrine one:

the fake one:

Now symfony’s autowire automatically provide us with the proper implementation in each environment. so now let’s get into our tests , here we can use both integration tests or application test that symfony provide us the infrastructures of. I’m gonna showcase both of them. note that we can’t really write unit tests for our controller cause it needs to be instantiated by symfony’s kernel , the only way to be able to write truly UNIT tests is to separate our logic from the controller for example by using the use case from the Clean architecture , I might write some articles on this in future , let me know.

Before starting to write tests you need to have the symfony/test-pack package installed , if not run composer require --dev symfony/test-pack

Integration test aka kernel test

here we’ve booted symfony’s kernel and asked it to handle our request which is manually created , then we have asserted the result with the post title that we have provided in our fake repository. (Post([‘id’ => 1, ‘title’ => ‘test title 1’]))

Application test aka WebTest

here we are creating a client to send a GET request to our route and then after asserting that the response is successful we are checking the post title with id of 2.

Now we can run the php bin/phpunit command and see the results:

as you can see our tests are successful without any access to database, in fact I haven’t even created the default database for testing which even if it’s not specified in the .env.test file it’s the .env database name with _test suffix.

here’s the full example if you want to explore



learning is my dopamine

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store