Тестирование

Как только вы пишете новую строку кода, вы также потенциально добавляете новые ошибки. Для того чтобы создавать более надёжные приложения, вы должны тестировать их, используя как функциональные, так и модульные (unit) тесты.

Тестовый фреймворк PHPUnit

В Symfony интегрирована независимая библиотека (называемая PHPUnit), которая предоставляет вам отличный тестовый фреймворк. Эта глава не покрывает все нюансы PHPUnit, но у него есть своя подробная документация.

Note

Рекомендуется использовать самую последнюю устойчивую версию PHPUnit, установленную как PHAR.

Каждый тест, вне зависимости от того, функциональный он или модульный, – это PHP класс, который должен быть расположен в каталоге tests/ вашего приложения. Если вы будете следовать этому правилу, то вы сможете запускать все тестирования вашего приложения при помощи следующей команды:

1
$ phpunit

PHPUnit создается файлом phpunit.xml.dist, в корне вашего приложения Symfony.

Tip

Зону действия кода можно создать с помощью опций --coverage-*, смотрите справочную информацию, которая отображается при использовании --help.

Модульные тесты

Модульный тест – это, как правило, тест одного отдельного PHP класса, также называемого модулем. Если вы хотите тестировать поведение вашего приложения целиком, обратитесь к секции Функциональные тесты `Functional Tests`_.

Написание модульных тестов в Symfony не отличается от написания стандартных модульных тестов PHPUnit. Например, предположим, у вас есть очень простой класс Calculator в каталоге Util/ пакета приложения:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// src/AppBundle/Util/Calculator.php
namespace AppBundle\Util;

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

Для того, чтобы его протестировать, создайте файл CalculatorTest в каталоге ``tests/AppBundle/Util` вашего приложения:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// tests/AppBundle/Util/CalculatorTest.php
namespace Tests\AppBundle\Util;

use AppBundle\Util\Calculator;
use PHPUnit\Framework\TestCase;

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

        // убедитесь, что ваш калькулятор добавил цифры правильно!
        $this->assertEquals(42, $result);
    }
}

Note

По соглашению, каталог tests/AppBundle должен повторять структуру каталогов вашего пакета для модульных тестов. Таким образом, если вы тестируете класс в каталоге src/AppBundle/Util/, поместите тест в каталог tests/AppBundle/Util/.

Так же, как и в вашем настоящем приложении, автозагрузка включается автоматически при помощи файла app/autoload.php``(это настроено по умолчанию в файле ``phpunit.xml.dist).

Выполнить тесты для заданного файла или папки также очень просто:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# запустить все тесты в приложении
$ phpunit

# запустить все тесты в каталоге Util
$ phpunit tests/AppBundle/Util

# запустить тесты в классе Calculator
$ phpunit tests/AppBundle/Util/CalculatorTest.php

# запустить все тесты для всего пакета
$ phpunit tests/AppBundle/

Функциональные тесты

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:

  • Make a request;
  • Test the response;
  • Click on a link or submit a form;
  • Test the response;
  • Rinse and repeat.

Your First Functional Test

Функциональные тесты - это простые PHP-файлы, которые обычно находятся в каталоге tests/AppBundle/Controller вашего пакета. Если вы хотите протестировать страницы, которые управляются вашим классом PostController, начните с создания нового файла PostControllerTest.php, который расширяет специальный класс WebTestCase.

В качестве примера, тест может выглядеть так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// tests/AppBundle/Controller/PostControllerTest.php
namespace Tests\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class PostControllerTest extends WebTestCase
{
    public function testShowPost()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', '/post/hello-world');

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

Tip

Для запуска ваших функциональных тестов, класс WebTestCase загружает ядро вашего приложения. В большинстве случаев, это происходит автоматически. Тем не менее, если ваше ядро находится в нестандартном каталоге, вам нужно модифицировать файл phpunit.xml.dist и установить переменную среды KERNEL_DIR на каталог вашего ядра:

1
2
3
4
5
6
7
<?xml version="1.0" charset="utf-8" ?>
<phpunit>
    <php>
        <server name="KERNEL_DIR" value="/path/to/your/app/" />
    </php>
    <!-- ... -->
</phpunit>

Метод createClient() возвращает клиент, который напоминает браузер, который вы используете для просмотра вашего сайта:

1
$crawler = $client->request('GET', '/post/hello-world');

Метод request() (смотрите больше о методе request) возвращает объект Crawler, который может быть использован для выбора элементов в ответе, кликов по ссылкам и отправки форм.

Tip

Crawler (поисковый агент, «гусеница») может использоваться только в том случае, если ответ – это XML или HTML документ. Для других типов нужно получать содержимое вызвав $client->getResponse()->getContent().

Кликните по ссылке, выбрав её при помощи Crawler используя выражение XPath или CSS селектор, затем используйте клиент для клика. Например:

1
2
3
4
5
6
7
8
$link = $crawler
    ->filter('a:contains("Greet")') // find all links with the text "Greet"
    ->eq(1) // select the second link in the list
    ->link()
;

// и кликните по ней
$crawler = $client->click($link);

Отправка формы происходит очень схожим образом: выберите кнопку на форме, по желанию переопределите какие-нибудь значения формы, и отправьте соответствующую форму: Submitting a form is very similar: sele:

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

// установить некоторые значения $form['name'] = 'Lucas'; $form['form_name[subject]'] = 'Hey there!';

// предоставить форму $crawler = $client->submit($form);

Tip

Форма также может поддерживать загрузку файлов и содержит методы для заполнения различных типов полей (например, select() и tick()). Подробнее читайте в секции `_Формы`_ `Forms`_ ниже.

Теперь, когда вы с лёгкостью можете перемещаться по приложению, воспользуйтесь утверждениями, чтобы проверить ожидаемые действия. Воспользуйтесь Crawler чтобы сделать утверждения для DOM:

1
2
// Утверждает, что ответ соотвествует заданному CSS селектору.
$this->assertGreaterThan(0, $crawler->filter('h1')->count());

Или протестируйте содержимое ответа напрямую, если хотите убедиться что его содержимое включает какой-либо текст, или что он не является документом XML/HTML:

1
2
3
4
$this->assertContains(
    'Hello World',
    $client->getResponse()->getContent()
);

Для быстрого старта, обратите внимание на список наиболее распространенных и полезных утверждений:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
use Symfony\Component\HttpFoundation\Response;

// ...

// Утверждает, что имеется единственный тег h2
// с классом "subtitle"
$this->assertGreaterThan(
    0,
    $crawler->filter('h2.subtitle')->count()
);

// Утверждает, что на странице имеется только 4 тега h2
$this->assertCount(4, $crawler->filter('h2'));

// Утверждает, что заголовок "Content-Type" - "application/json"
$this->assertTrue(
    $client->getResponse()->headers->contains(
        'Content-Type',
        'application/json'
    ),
    'the "Content-Type" header is "application/json"' // optional message shown on failure
);

// Увтерждает, что соержимое ответа содержит строку
$this->assertContains('foo', $client->getResponse()->getContent());
// ...или совпадает с регулярным выражением
$this->assertRegExp('/foo(bar)?/', $client->getResponse()->getContent());

// Утверждает, что статус-код ответа является 2xx
$this->assertTrue($client->getResponse()->isSuccessful(), 'response status is 2xx');
// Увтерждает, что статус-код ответа является 404
$this->assertTrue($client->getResponse()->isNotFound());
// Утверждает что статус-код ответа точно 200
$this->assertEquals(
    200, // or Symfony\Component\HttpFoundation\Response::HTTP_OK
    $client->getResponse()->getStatusCode()
);

// Утверждает что ответ - это перенаправление на /demo/contact
$this->assertTrue(
    $client->getResponse()->isRedirect('/demo/contact')
    // if the redirection URL was generated as an absolute URL
    // $client->getResponse()->isRedirect('http://localhost/demo/contact')
);
// ...или просто проверяет, что ответ - это перенаправление на любой URLL
$this->assertTrue($client->getResponse()->isRedirect());

Работа с тестовым клиентом

Тестовый клиент симулирует HTTP клиент (типа браузера) и выполняет запросы к вашему Symfony приложению:

1
$crawler = $client->request('GET', '/post/hello-world');

Метод request() принимает HTTP метод и URL в качестве аргументов, и возвращает экземпляр Crawler.

Tip

Жестко запрограмированные URL – это лучшее решение для функциональных тестов. Если тест генерирует URLы используя маршрутизатор Symfony, он не обнаружит никаких изменений, сделанных в URLах приложения, что может повлиять на конечного пользователя.

Полная сигнатура метода request() выглядит так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    request(
        $method,
        $uri,
        array $parameters = array(),
        array $files = array(),
        array $server = array(),
        $content = null,
        $changeHistory = true
    )

Массив ``server``  это сырые значения, которые вы обычно можете найти в
суперглобальном PHP `$_SERVER`_. Например, чтобы установить HTTP заголовки
 ``Content-Type``,  ``Referer`` и ``X-Requested-With``, вам нужно будет
 сделать следующее (не забывайте об ``HTTP_`` приставке для нестандартных
 заголовков)::

    $client->request(
        'GET',
        '/post/hello-world',
        array(),
        array(),
        array(
            'CONTENT_TYPE'          => 'application/json',
            'HTTP_REFERER'          => '/foo/bar',
            'HTTP_X-Requested-With' => 'XMLHttpRequest',
        )
    );

Используйте Crawler для нахождения DOM-элементов в теле ответа. После, эти элементы могут быть использованы для кликов по ссылкам и отправки форм:

1
2
3
4
5
$link = $crawler->selectLink('Go elsewhere...')->link();
$crawler = $client->click($link);

$form = $crawler->selectButton('validate')->form();
$crawler = $client->submit($form, array('name' => 'Fabien'));

Оба метода click() и submit() возвращают объект Crawler. Эти методы - лучший способ просматривать ваше приложение, так как они заботятся о многих вещах, например, об определении HTTP метода формы, и предоставлении вам удобного API для загрузки файлов.

Tip

Больше узнать об объектах Link и Form можно в разделе Crawler ниже.

Метод request() может также быть использован для симуляции отправки форм или для выполнения более сложных запросов. Вот некоторые полезные примеры:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Прямая отправка формы (можно и так, но легче использовать Crawler!)
$client->request('POST', '/submit', array('name' => 'Fabien'));

// Отправка строки JSON в тело запроса
$client->request(
    'POST',
    '/submit',
    array(),
    array(),
    array('CONTENT_TYPE' => 'application/json'),
    '{"name":"Fabien"}'
);

// Отправка формы с загрузкой файла
use Symfony\Component\HttpFoundation\File\UploadedFile;

$photo = new UploadedFile(
    '/path/to/photo.jpg',
    'photo.jpg',
    'image/jpeg',
    123
);
$client->request(
    'POST',
    '/submit',
    array('name' => 'Fabien'),
    array('photo' => $photo)
);

// Выполнение DELETE запросов, и отправка HTTP заголовков
$client->request(
    'DELETE',
    '/post/12',
    array(),
    array(),
    array('PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word')
);

И последнее, но не менее важное, можно заставить каждый запрос выполняться в собственном PHP процессе, чтобы избежать любых побочных эффектов когда несколько клиентов работают в одном скрипте:

1
$client->insulate();

Браузинг

Клиент поддерживает многие операции, которые можно выполнить в настоящем браузере:

1
2
3
4
5
6
$client->back();
$client->forward();
$client->reload();

// Очищает все куки и историю.
$client->restart();

Получение доступа к внутренним объектам

Если вы используете клиент для тестирования своего приложения, вам может понадобиться получить доступ к его внутренним объектам:

1
2
$history = $client->getHistory();
$cookieJar = $client->getCookieJar();

Вы также можете получить объекты, относящиеся к последнему запросу:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// экземпляр запроса HttpKernel
$request = $client->getRequest();

// экземпляр запроса BrowserKit
$request = $client->getInternalRequest();

// экземпляр ответа the HttpKernel
$response = $client->getResponse();

// экземпляр ответа BrowserKit
$response = $client->getInternalResponse();

$crawler = $client->getCrawler();

Получение доступа к контейнеру

Настоятельно рекомендуется использовать функциональные тесты только для проверки ответов. Но в некоторых крайне редких случаях, вам может понадобиться получить доступ к некоторым внутренним объектам для написания утверждений. В таких случаях, вы можете использовать контейнер внедрения зависимости:

1
2
3
4
// это будет тот же контейнер, что используется в вашем тесте, кроме случаев,
// когда вы используете $client->insulate() или настоящие HTTP-запросы для
// тестирования вашего приложения
$container = $client->getContainer();

Чтобы получить список сервисов, существующих в вашем приложении, используйте команду debug:container.

Tip

Если необходимая для проверки информация доступна из профилировщика, тогда используйте его.

Получение доступа к данным профайлера

Для каждого запроса, вы можете активировать профайлер Symfony для сбора данных о внутренней обработке этого запроса. Например, профайлер может быть использован для верификации того, что данная страница во время загрузки выполняет меньше SQL запросов, чем заданное пороговое значение.

Для получения профайлера для последнего запроса выполните следующий код:

1
2
3
4
5
6
7
// включить профайлер для следующего запроса
$client->enableProfiler();

$crawler = $client->request('GET', '/profiler');

// получить профиль
$profile = $client->getProfile();

Подробнее про использование профайлера в тестах читайте в статье Как использовать профайлер в функциональном тесте.

Перенаправление

Когда запрос возвращает ответ с перенаправлением, клиент не следует ему автоматически. Вы можете изучить ответ, и заставить клиент произвести перенаправление с помощью метода followRedirect():

1
$crawler = $client->followRedirect();

Если вы хотите, чтобы клиент автоматически следовал всем перенаправлениям, вы можете заставить его делать это с помощью метода followRedirects():

1
$client->followRedirects();

Если вы переадите в метод followRedirects() значение false, то клиент больше не будет следовать перенаправлениям:

1
$client->followRedirects(false);

Crawler

Экземпляр Crawler возвращается каждый раз, когда выполняется запрос посредством клиента. Он позволяет вам перемещаться по HTML документам, выбирать узлы, искать ссылки и формы.

Перемещения

Как и jQuery, Crawler имеет методы для перемещения по DOM документа HTML/XML. Например, следующий код находит все элементы input[type=submit], выбирает последний на странице, и потом выбирает ближайший родительский элемент:

1
2
3
4
5
$newCrawler = $crawler->filter('input[type=submit]')
    ->last()
    ->parents()
    ->first()
;

Также доступны многие другие методы:

filter('h1.title')
Узлы, соответствующие CSS селектору.
filterXpath('h1')
Узлы, соответствующие выражению XPath.
eq(1)
Узлы для определенного индекса.
first()
Первый узел.
last()
Последний узел.
siblings()
Элементы одного уровня (сестры).
nextAll()
Все последующие сестры.
previousAll()
Все предыдущие сестры.
parents()
Возвращает родительские узлы.
children()
RВозвращает узлы потомков.
reduce($lambda)
Узлы, для которых функция не возвращает false.

Так как каждый из этих методов возвращает новый экземпляр Crawler, вы можете упростить ваш код путём выстраивания методов вызова в цепочку:

1
2
3
4
5
6
7
8
9
$crawler
    ->filter('h1')
    ->reduce(function ($node, $i) {
        if (!$node->getAttribute('class')) {
            return false;
        }
    })
    ->first()
;

Tip

Используйте функцию count(), чтобы получить количество узлов, хранящихся в Crawler: count($crawler)

Извлечение информации

Crawler может извлекать информацию из узлов:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Возвращает значение атрибута для первого узла
$crawler->attr('class');

// Возвращает значение узла для первого узла
$crawler->text();

// Извлекает массив аттрибутов для всех узлов
// (_text returns the node value)
// Возвращает массив для каждого элемента
// с его значением и ссылкой
$info = $crawler->extract(array('_text', 'href'));

// Выполняет lambda для каждого узла и возвращает массив результатов
$data = $crawler->each(function ($node, $i) {
    return $node->attr('href');
});

Ссылки

Для выбора ссылок вы можете использовать методы обхода, указанных выше, или более удобное сокращение selectLink():

1
$crawler->selectLink('Click here');

Оно выбирает все ссылки, содержащие указанный текст, либо изображения, по которым можно кликать, содержащие этот текст в атрибуте alt. Как и другие методы фильтрации, он возращает еще один объект Crawler.

После того, как вы выбрали ссылку, у вас есть доступ к специальному объекту Link, который содержит специальные полезные методы для ссылок (например, getMethod() и getUri()). Чтобы кликнуть по ссылке, используйте метод клиента click() и добавьте в него объект Link:

1
2
3
$link = $crawler->selectLink('Click here')->link();

$client->click($link);

Формы

Формы можно выбирать используя их кнопки, которые можно выбрать с помощью метода selectButton(), точно так же, как и ссылки:

1
$buttonCrawlerNode = $crawler->selectButton('submit');

Note

Заметьте, что вы выбираете кнопку на форме, а не саму форму, т. к. форма может иметь несколько кнопок; если вы используюте API перемещений, то помните, что вам надо искать кнопку.

Метод selectButton() может выбрать теги button и представлять теги input. Он ипользует несколько частей кнопок для их нахождения:

  • Значение атрибута value;
  • Значение атрибута id или аlt для изображений;
  • Значение атрибута id или name для тегов button.

Как только у вас есть Crawler, представляющий кнопку, вызовите метод form() для получения экзмепляра Form для формы, описывающей узел кнопки:

1
$form = $buttonCrawlerNode->form();

При вызове метода form(), вы также можете передать массив значений для полей, перезаписывающих начальные значения:

1
2
3
4
$form = $buttonCrawlerNode->form(array(
    'name'              => 'Fabien',
    'my_form[subject]'  => 'Symfony rocks!',
));

А если вы хотите симулировать определённый HTTP метод для формы, передайте его вторым аргументом:

1
$form = $buttonCrawlerNode->form(array(), 'DELETE');

Клиент может отправлять эзкемпляры Form:

1
$client->submit($form);

Значения полей также могут быть переданы вторым аргументом метода submit():

1
2
3
4
$client->submit($form, array(
    'name'              => 'Fabien',
    'my_form[subject]'  => 'Symfony rocks!',
));

В более сложных случаях, используйте экземпляр Form как массив, чтобы задать значения каждого поля индивидуально:

1
2
3
// Изменить значение поля
$form['name'] = 'Fabien';
$form['my_form[subject]'] = 'Symfony rocks!';

Также имеется красивый API для управления значениями полей в зависимости от их типа:

1
2
3
4
5
6
7
8
// Выбрать option или radio
$form['country']->select('France');

// Поставить галочку в checkbox
$form['like_symfony']->tick();

// Загрузить файл
$form['photo']->upload('/path/to/lucas.jpg');

Tip

Если вы хотите намеренно выбрать «ошибочные» (invalid) значения select/radio, смотрите Выбор ошибочных значений components-dom-crawler-invalid.

Tip

Вы можете получить значения, которые будут отправлены, вызвав метод getValues() объекта Form. Загружаемые файлы доступны в отдельном массиве, возвращаемом через getFiles(). Методы getPhpValues() и getPhpFiles()) тоже возвращают отправленные значения, но в формате PHP (он преобразует ключи с квадратными скобками - например, my_form[subject] - в PHP массивы).

Добавление и удаление форм из Коллекции

Если вы используете Коллекцию форм, то вы не можете добавить поля в существующую форму с помощью $form['task[tags][0][name]'] = 'foo';. Это приведет к ошибке Unreachable field "…" (Недоступное поле «…»), так как $form можно использовать только для того, чтобы устанавливать значения для существующих полей. Для того, чтобы добавить новые поля, вам необходимо добавить значения к сырому массиву данных:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Получить форму.
$form = $crawler->filter('button')->form();

// Получить сырые значения.
$values = $form->getPhpValues();

// AДобавить поля к сырым значениям.
$values['task']['tags'][0]['name'] = 'foo';
$values['task']['tags'][1]['name'] = 'bar';

// Предоставить форму с существующими и новыми значениями.
$crawler = $client->request($form->getMethod(), $form->getUri(), $values,
    $form->getPhpFiles());

// 2 тега были добавлены в коллекцию.
$this->assertEquals(2, $crawler->filter('ul.tags > li')->count());

Где task[tags][0][name] – это имя поля, созданного JavaScript.

Вы можете удалить существующее поле, например тег:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Получить значения формы.
$values = $form->getPhpValues();

// Удалить первый тег.
unset($values['task']['tags'][0]);

// Предоставить данные.
$crawler = $client->request($form->getMethod(), $form->getUri(),
    $values, $form->getPhpFiles());

//  Тег был удален.
$this->assertEquals(0, $crawler->filter('ul.tags > li')->count());

Тестовая конфигурация

Клиент, используемый функциональными тестами, создает Kernel (ядро), которое находится в специальном окружении test. Так как Symfony загружает app/config/config_test.yml в окружении test, вы можете скорректировать любые настройки вашего приложения специально для тестирования.

Например, по умолчанию, Swift Mailer сделан так, чтобы не доставлять имейлы в окружение test. Вы можете увидеть это в опции конфигурации swiftmailer:

  • YAML
    1
    2
    3
    4
    5
    # app/config/config_test.yml
    
    # ...
    swiftmailer:
        disable_delivery: true
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- app/config/config_test.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:swiftmailer="http://symfony.com/schema/dic/swiftmailer"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/swiftmailer
            http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd">
    
        <!-- ... -->
        <swiftmailer:config disable-delivery="true" />
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // app/config/config_test.php
    
    // ...
    $container->loadFromExtension('swiftmailer', array(
        'disable_delivery' => true,
    ));
    

Вы также можете использовать полностью другое окружение, или переписать метод отлаживания по умолчанию (true) путем передавания каждого в качестве опций в методе createClient():

1
2
3
4
$client = static::createClient(array(
    'environment' => 'my_test_env',
    'debug'       => false,
));

Если ваше приложение ведет себя в соответствии с некоторыми заголовками HTTP, передайте их в качестве второго аргумента в createClient():

1
2
3
4
$client = static::createClient(array(), array(
    'HTTP_HOST'       => 'en.example.com',
    'HTTP_USER_AGENT' => 'MySuperBrowser/1.0',
));

Вы также можете переписать заголовки HTTP на основании запросов:

1
2
3
4
$client->request('GET', '/', array(), array(), array(
    'HTTP_HOST'       => 'en.example.com',
    'HTTP_USER_AGENT' => 'MySuperBrowser/1.0',
));

Tip

Тестовый клиент доступен в виде сервиса в контейнере окружения test (или там, где подключена опция тестового фреймворка framework.test). Это значит, что вы можете переписать сервис полностью, если вам это необходимо.

Конфигурация PHPUnit

Каждое приложение имеет свою собственную конфигурацию PHPUnit, которая хранится в файле phpunit.xml.dist. Вы можете редактировать этот файл, чтобы менять значения по умолчанию, или же вы можете создать файл phpunit.xml для установки конфигурации только для вашей локальной машины.

Tip

Сохраните файл phpunit.xml.dist в вашем репозитории кода и игнорируйте файл phpunit.xml.

По умолчанию, по команде phpunit запускаются только тесты, которые хранятся в /tests, так задано в файле phpunit.xml.dist:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- phpunit.xml.dist -->
<phpunit>
    <!-- ... -->
    <testsuites>
        <testsuite name="Project Test Suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
    <!-- ... -->
</phpunit>

Но вы можете с легкостье добавить больше каталогов. например, следующая конфигурация, добавляет тесты из пользовательского каталога lib/tests:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- phpunit.xml.dist -->
<phpunit>
    <!-- ... -->
    <testsuites>
        <testsuite name="Project Test Suite">
            <!-- ... --->
            <directory>lib/tests</directory>
        </testsuite>
    </testsuites>
    <!-- ... --->
</phpunit>

Чтобы добавить другие каталоги в охват кода, также внесите правки в часть <filter>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!-- phpunit.xml.dist -->
<phpunit>
    <!-- ... -->
    <filter>
        <whitelist>
            <!-- ... -->
            <directory>lib</directory>
            <exclude>
                <!-- ... -->
                <directory>lib/tests</directory>
            </exclude>
        </whitelist>
    </filter>
    <!-- ... --->
</phpunit>

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.