Testing Twig Extensions The Right Way

In the previous article, I wrote how to improve your application’s response time with lazy Twig extensions. Let’s test them properly now.

.com software
3 min readJan 5, 2022
A handsome, young Afro-American  man pointing on his temple thinking: “no tests? More time for coding”

Before diving into this story make sure you have already read my story on “how to create a Lazy Twig Extension” or that you understand what it is and how it works.

Our app is fast & furious now, using lazy ArticleTagExtension that does its job done. Now is the time to unit test it to ensure our app won’t break.

Installing PHPUnit

Official Twig testing framework expects PHPUnit to be installed. In case we don’t have it installed yet (really?) we’re going to quickly fix the issue
php composer.phar req --dev phpunit/phpunit ^8.0 which is going to download a pretty decent version of it.

We’ll add the tests directory for our tests and quickly update the composer.json file to tell PHP where our test classes are:

"autoload-dev": {
"psr-4": {
"Test\\App\\": "tests"
}
}

Creating a test suite

There’s a handy PHPUnit test suite class called IntegrationTestCase that takes the heavy lifting. It’s purpose is to test Twig’s extensions in an isolated environment.

Let’s create the test class in the tests/Twig/Extension directory:

In its most basic form it requires:

  • to return the path to the directory in which the class expects to find “Twig tests” (files matching the *.test pattern anywhere in this directory)
  • to return extensions the “Twig tests” are going to use

A Twig test is supposed to be in the following format:

--TEST--
Describe here what & why is being tested
--TEMPLATE--
Twig Template of the test
--DATA--
Eval'ed PHP expression to use as the template parameters
--EXPECT--
The expected output of parsed "Template" with the "Data"

Since our extension now uses a runtime, the tests require a runtime loader that will load. Let’s modify the test to enable it. I have written a simple implementation of the ArticleRepository to mock the dependency and rule out database access. You could use mocks, but I prefer solid implementations:

And the most important part, the test itself! A file named tests/Twig/Extension/function/get_tags.test

--TEST--
get_tags function should return a list of tags

--TEMPLATE--
{{ get_tags(tag_count)|join(', ') }}

--DATA--
return [
'tag_count' => 5,
]

--EXPECT--
dogs, cats, pigs, pigeons, monkeys

The variable tag_count is unnecessary, acts as a showcase of how to use test parameters. If you don’t wish to use any, you can simply leave return []

As soon as we run the tests (the --exclude-group of legacy is necessary to avoid an unused test case which would otherwise be reported as “skipped”):

vendor/bin/phpunit --exclude-group=legacy --bootstrap vendor/autoload.php tests

We end up green!

OK (1 test, 2 assertions)

Have any questions? Feel free to hit me up in the comments. The code is available publicly under an MIT license on GitHub. Happy testing!

--

--

.com software

Father • PHP developer • entrepreneur • working for a €1bn unicorn startup as a backend engineer >>> https://bit.ly/dotcom-software