Testing¶
Because PrestoPHP is built on top of Symfony, it is very easy to write functional tests for your application. Functional tests are automated software tests that ensure that your code is working correctly. They go through the user interface, using a fake browser, and mimic the actions a user would do.
Why¶
If you are not familiar with software tests, you may be wondering why you would need this. Every time you make a change to your application, you have to test it. This means going through all the pages and making sure they are still working. Functional tests save you a lot of time, because they enable you to test your application in usually under a second by running a single command.
For more information on functional testing, unit testing, and automated software tests in general, check out PHPUnit and Bulat Shakirzyanov’s talk on Clean Code.
PHPUnit¶
PHPUnit is the de-facto
standard testing framework for PHP. It was built for writing unit tests, but it
can be used for functional tests too. You write tests by creating a new class,
that extends the PHPUnit\Framework\TestCase
. Your test cases are methods
prefixed with test
:
use PHPUnit\Framework\TestCase;
class ContactFormTest extends TestCase
{
public function testInitialPage()
{
...
}
}
In your test cases, you do assertions on the state of what you are testing. In this case we are testing a contact form, so we would want to assert that the page loaded correctly and contains our form:
public function testInitialPage()
{
$statusCode = ...
$pageContent = ...
$this->assertEquals(200, $statusCode);
$this->assertContains('Contact us', $pageContent);
$this->assertContains('<form', $pageContent);
}
Here you see some of the available assertions. There is a full list available in the Writing Tests for PHPUnit section of the PHPUnit documentation.
WebTestCase¶
Symfony provides a WebTestCase class that can be used to write functional
tests. The PrestoPHP version of this class is PrestoPHP\WebTestCase
, and you can
use it by making your test extend it:
use PrestoPHP\WebTestCase;
class ContactFormTest extends WebTestCase
{
...
}
Caution
If you need to override the setUp()
method, don’t forget to call the
parent (parent::setUp()
) to call the PrestoPHP default setup.
Note
If you want to use the Symfony WebTestCase
class you will need to
explicitly install its dependencies for your project:
composer require --dev symfony/browser-kit symfony/css-selector
For your WebTestCase, you will have to implement a createApplication
method, which returns your application instance:
public function createApplication()
{
// app.php must return an Application instance
return require __DIR__.'/path/to/app.php';
}
Make sure you do not use require_once
here, as this method will be
executed before every test.
Tip
By default, the application behaves in the same way as when using it from a
browser. But when an error occurs, it is sometimes easier to get raw
exceptions instead of HTML pages. It is rather simple if you tweak the
application configuration in the createApplication()
method like
follows:
public function createApplication()
{
$app = require __DIR__.'/path/to/app.php';
$app['debug'] = true;
unset($app['exception_handler']);
return $app;
}
Tip
If your application use sessions, set session.test
to true
to
simulate sessions:
public function createApplication()
{
// ...
$app['session.test'] = true;
// ...
}
The WebTestCase provides a createClient
method. A client acts as a browser,
and allows you to interact with your application. Here’s how it works:
public function testInitialPage()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/');
$this->assertTrue($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('h1:contains("Contact us")'));
$this->assertCount(1, $crawler->filter('form'));
...
}
There are several things going on here. You have both a Client
and a
Crawler
.
You can also access the application through $this->app
.
Client¶
The client represents a browser. It holds your browsing history, cookies and
more. The request
method allows you to make a request to a page on your
application.
Note
You can find some documentation for it in the client section of the testing chapter of the Symfony documentation.
Crawler¶
The crawler allows you to inspect the content of a page. You can filter it using CSS expressions and lots more.
Note
You can find some documentation for it in the crawler section of the testing chapter of the Symfony documentation.
Configuration¶
The suggested way to configure PHPUnit is to create a phpunit.xml.dist
file, a tests
folder and your tests in
tests/YourApp/Tests/YourTest.php
. The phpunit.xml.dist
file should
look like this:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<testsuites>
<testsuite name="YourApp Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
</phpunit>
Your tests/YourApp/Tests/YourTest.php
should look like this:
namespace YourApp\Tests;
use PrestoPHP\WebTestCase;
class YourTest extends WebTestCase
{
public function createApplication()
{
return require __DIR__.'/../../../app.php';
}
public function testFooBar()
{
...
}
}
Now, when running phpunit
on the command line, tests should run.