scribble

Xujiajun Blog

About Blog Email GitHub

30 May 2014
Testing [第10天]

Whenever you write a new line of code, you also potentially add new bugs. To build better and more reliable applications, you should test your code using both functional and unit tests.

The PHPUnit Testing Framework¶

Symfony2 integrates with an independent library - called PHPUnit - to give you a rich testing framework. This chapter won’t cover PHPUnit itself, but it has its own excellent documentation.

Tips:

Symfony2 works with PHPUnit 3.5.11 or later, though version 3.6.4 is needed to test the Symfony core code itself.

Each test - whether it’s a unit test or a functional test - is a PHP class that should live in the Tests/ subdirectory of your bundles. If you follow this rule, then you can run all of your application’s tests with the following command:

# specify the configuration directory on the command line
$ phpunit -c app/

The -c option tells PHPUnit to look in the app/ directory for a configuration file. If you’re curious about the PHPUnit options, check out the app/phpunit.xml.dist file.

Tips:

Code coverage can be generated with the –coverage-html option.

Unit Tests¶

A unit test is usually a test against a specific PHP class. If you want to test the overall behavior of your application, see the section about Functional Tests.

Writing Symfony2 unit tests is no different than writing standard PHPUnit unit tests. Suppose, for example, that you have an incredibly simple class called Calculator in the Utility/ directory of your bundle:

// src/Acme/DemoBundle/Utility/Calculator.php
namespace Acme\DemoBundle\Utility;

class Calculator
{
    public function add($a, $b)
    {
        return $a + $b;
    }
}

To test this, create a CalculatorTest file in the Tests/Utility directory of your bundle:

// src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php
namespace Acme\DemoBundle\Tests\Utility;

use Acme\DemoBundle\Utility\Calculator;

class CalculatorTest extends \PHPUnit_Framework_TestCase
{
    public function testAdd()
    {
        $calc = new Calculator();
        $result = $calc->add(30, 12);

        // assert that your calculator added the numbers correctly!
        $this->assertEquals(42, $result);
    }
}

Tips:

By convention, the Tests/ sub-directory should replicate the directory of your bundle. So, if you’re testing a class in your bundle’s Utility/ directory, put the test in the Tests/Utility/ directory.

Just like in your real application - autoloading is automatically enabled via the bootstrap.php.cache file (as configured by default in the app/phpunit.xml.dist file).

Running tests for a given file or directory is also very easy:

# run all tests in the Utility directory
$ phpunit -c app src/Acme/DemoBundle/Tests/Utility/

# run tests for the Calculator class
$ phpunit -c app src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php

# run all tests for the entire Bundle
$ phpunit -c app src/Acme/DemoBundle/

Functional Tests¶

Functional tests check the integration of the different layers of an application (from the routing to the views). They are no different from unit tests as far as PHPUnit is concerned, but they have a very specific workflow:

1、Make a request; 2、Test the response; 3、Click on a link or submit a form; 4、Test the response; 5、Rinse and repeat.

Your First Functional Test¶

Functional tests are simple PHP files that typically live in the Tests/Controller directory of your bundle. If you want to test the pages handled by your DemoController class, start by creating a new DemoControllerTest.php file that extends a special WebTestCase class.

For example, the Symfony2 Standard Edition provides a simple functional test for its DemoController (DemoControllerTest) that reads as follows:

// src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php
namespace Acme\DemoBundle\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class DemoControllerTest extends WebTestCase
{
    public function testIndex()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', '/demo/hello/Fabien');

        $this->assertGreaterThan(
            0,
            $crawler->filter('html:contains("Hello Fabien")')->count()
        );
    }
}

Tips:

To run your functional tests, the WebTestCase class bootstraps the kernel of your application. In most cases, this happens automatically. However, if your kernel is in a non-standard directory, you’ll need to modify your phpunit.xml.dist file to set the KERNEL_DIR environment variable to the directory of your kernel:

<phpunit>
    <!-- ... -->
    <php>
        <server name="KERNEL_DIR" value="/path/to/your/app/" />
    </php>
    <!-- ... -->
</phpunit>

The createClient() method returns a client, which is like a browser that you’ll use to crawl your site:

$crawler = $client->request('GET', '/demo/hello/Fabien');

The request() method (see more about the request method) returns a Crawler object which can be used to select elements in the Response, click on links, and submit forms.

Tips:

The Crawler only works when the response is an XML or an HTML document. To get the raw content response, call $client->getResponse()->getContent().

Click on a link by first selecting it with the Crawler using either an XPath expression or a CSS selector, then use the Client to click on it. For example, the following code finds all links with the text Greet, then selects the second one, and ultimately clicks on it:

$link = $crawler->filter('a:contains("Greet")')->eq(1)->link();

$crawler = $client->click($link);

Submitting a form is very similar; select a form button, optionally override some form values, and submit the corresponding form:

$form = $crawler->selectButton('submit')->form();

// set some values
$form['name'] = 'Lucas';
$form['form_name[subject]'] = 'Hey there!';

// submit the form
$crawler = $client->submit($form);

Tips:

The form can also handle uploads and contains methods to fill in different types of form fields (e.g. select() and tick()). For details, see the Forms section below.

Now that you can easily navigate through an application, use assertions to test that it actually does what you expect it to. Use the Crawler to make assertions on the DOM:


Til next time,
Xujiajun at 08:35

scribble

About Blog Email GitHub