Codeception Testing Framework from its roots was a plugin of symfony 1 framework. Today Codeception is powered by Symfony components and can be used to run functional tests for practically any popular PHP framework.
Why would you someone ever choose Codeception if Symfony already has mature testing infrastructure. Well, here are our reasons. Codeception tests are:
- fast, as each functional/integration test is wrapped into transaction using Doctrine ORM
- scenario-driven, it means that tests are linear, described in easy to get PHP DSL
- can be used for testing complex interactions inside functional tests.
- easy to write, as Codeception already provides bundled actions and assertions for most popular use cases.
- combine all testing levels (acceptance, functional, unit) in one tool.
Today we will write how Codeception can be installed into a Symfony project and fit with its structure: we will put functional and unit tests to corresponding bundles, write acceptance tests for complete application, and use one runner to execute them all at once.
We will use official symfony-demo application in this example. Once you get it installed you should add Codeception testing framework to dev dependencies list in composer.json
:
As you may know Codeception has bootstrap
command which create common file structure for acceptance, functional, and unit tests. However, as we decided we will follow Symfony way and skip creating global functional and unit tests. So we start with bootstrapping empty project without predefined suites.
As you may see, we got new tests
directory and codeception.yml
file created. Let’s have acceptance tests there:
Acceptance tests are expected to test the site from an end-user’s perspective. No matter how many unit tests you have in your projects you can’t get without acceptance testing. What if you see a blank page even all unit tests passed. How could this happen? Maybe you rendered wrong template, maybe some scripts or styles were not loaded. Those things can’t be handled with internal: unit or functional testing, however with acceptance tests you may be confident that UI is available for customers.
That’s why we recommend to have tests with real browser interaction. You can learn more about acceptance testing from our guides.
But what about unit and functional tests? As we decided we will put them into bundles. Symfony-demo has only AppBundle included, so we will create new Codeception setup in src/AppBundle
. Take a note that we want those tests to be placed in their own namespace:
We will also create unit
and functional
suites there:
As you noticed we specify path to different Codeception setup with -c
or --config
option.
Unit tests of Codeception are not quite different from regular PHPUnit tests. You can even copy your old PHPUnit tests to src/AppBundle/tests/unit
and have Codeception run them. It is much more interesting to use Codeception to have functional tests replacing ones extending Symfony\Bundle\FrameworkBundle\Test\WebTestCase
class.
Let’s have a test that will check that there is specific number of posts on a page. Symfony-demo app has the similar test included:
We will rewrite it in Codeception manner. At first we are generating new empty test case for it. We use scenario-driven test format called Cest:
And here goes the test:
As you see, Codeception test is shorter. It is simple, clean, and can be easily extended for more complex interactions. However, we are not ready to run it yet. We need to prepare Codeception to run functional tests inside Symfony context. For this we need to edit src/AppBundle/tests/functional.yml
configuration file to enable modules: Symfony2
and Doctrine2
to use:
The most important thing here is to provide valid app and var paths for Symfony. Also we are specifying that Doctrine’s EntityManager should be taken from Symfony DIC. Let’s run functional tests of AppBundle:
In this case you will see following output:
But you can do much more with functional testing. You can insert/assert data with Doctrine by using prepared methods like haveInRepository
, seeInRepository
of Doctrine2 module. You can perform complex web interactions like filling forms, clicking links, following redirects and much more with methods of Symfony2 module. Those modules are combined together and their methods are available in FunctionalTester
class you are supposed to use for writing functional tests. If you are interested to see more complex Codeception tests, we’ve got them for you.
Btw, you can use Symfony2 and Doctrine2 module for writing your unit and integration tests as well.
But how can we run acceptance tests of a project with tests from AppBundle together? We need to edit codeception.yml
configuration file in project root to make it. Let’s add those lines there:
That’s it. For now Codeception will include all installations stored in Bundles on run. If you execute:
you will probably see that BlogCest
of AppBundle
was executed as it was expected to.
The most complex thing in starting using Codeception with Symfony is have it configured. Despite Codeception is auto-connecting to Symfony framework and Doctrine you still have to do some changes to follow Symfony structure. Please take a detailed look into our forked version of symfony-demo project which we configured in the manner we described in this post. Please use similar configuration for all your Symfony projects.
Start using Codeception and discover how complex things can be tested in really simple manner. And once again, even functional and integration tests are really fast, as we start transaction before each test and rollback it afterwards. Write them as many as you need to, do not rely on unit tests only!
P.S. Symfony2 and Doctrine2 module is seeking for an active maintainer. If you work with Symfony and Codeception please contact us to join Codeception team!