Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel PHPUnit testing in integration tests

As the time needed for run complete PHPUnit suite raises, our team starts wondering if there is a possibility to run Unit tests in parallel. Recently I read an article about Paraunit, also Sebastian Bergman wrote, he'll add parallelism into PHPUnit 3.7.

But there remains the problem with integration tests, or, more generally, tests that interact with DB. For the sake of consistency, the testDB has to be resetted and fixtures loaded after each test. But in parallel tests there is a problem with race conditions, because all processes use the same DB.

So to be able to run integration tests in parallel, we have to assign own database to each process. I would like to ask, if someone has some thoughts about how this problem can be solved. Maybe there are already implemented solutions to this problem in another xUnit implementation.

In my team we are using MongoDB, so one solution would be to programmatically create a config file for each PHPUnit process, with generated DB name(for this process), and in setUp() method we could clone the main TestDb into this temporary one. But before we start to implement this approach I would like to ask for your ideas about the topic.

like image 670
hennadiy.verkh Avatar asked Jun 10 '13 08:06

hennadiy.verkh


2 Answers

This is a good question: preparing for parallel unit tests is going to require learning some new Best Practices, and I suspect some of them are going to slow our tests down.

At the highest level, the advice is: avoid testing with a database wherever possible. Abstract all interactions with your database, and then mock that class. But you've already noted your question is about integration tests, where this is not possible.

When using PDO, I generally use sqlite::memory: Each test gets its own database. It is anonymous and automatically cleaned up when the test ends. (But I noted some problems with this when you real application is not using sqlite: Suggestions to avoid DB deps when using an in-memory sqlite DB to speed up unit tests )

When using a database that does not have an in-memory choice, create the database with a random name. If the parallelization is at the PHPUnit process level, quite coarse, you could use the process pid. But that has no real advantages over a random name. (I know PHP is single-threaded, but perhaps in future we would have a custom phpUnit module, that uses threads to run tests in parallel; we might as well be ready for that.)

If you have the xUnit Test Patterns book, chapter 13 is about testing databases (relatively short). Chapters 8 and 9 on transient vs. persistent fixtures are useful too. And, of course, most of the book is on abstraction layers to make mocking easier :-)

like image 81
Darren Cook Avatar answered Sep 28 '22 06:09

Darren Cook


There is also this awesome library (fastest) for executing tests in parallel. It is optimized for functional/integration tests, giving an easy way to work with N databases in parallel.

Our old codebase run in 30 minutes, now in 7 minutes with 4 Processors.

Features

  • Functional tests could use a database per processor using the environment variable.
  • Tests are randomized by default.
  • Is not coupled with PhpUnit you could run any command.
  • Is developed in PHP with no dependencies.
  • As input you could use a phpunit.xml.dist file or use pipe.
  • Includes a Behat extension to easily pipe scenarios into fastest.
  • Increase Verbosity with -v option.

Usage

find tests/ -name "*Test.php" | ./bin/fastest "bin/phpunit -c app {};"

like image 35
Mohamed Ramrami Avatar answered Sep 28 '22 05:09

Mohamed Ramrami