test


Chaque fois que vous écrivez une ligne de code supplémentaire, vous ajoutez de nouveaux bugs potentiels. Afin de créer des programmes meilleurs et plus fiables, vous devez utiliser des tests fonctionnels et unitaires sur votre code.

PHPUnit framework de test

Symfony intègre une bibliothèque de classes indépendante - nommée PHPUnit - pour vous offrir un framework de test riche. Ce chapitre ne couvre pas PHPUnit lui-même, mais il possède sa propre Excellente documentation.

Il est recommandé d'utiliser la dernière version stable de PHPUnit, installe PHAR.

Chaque test – qu'il s'agisse d'un test unitaire ou d'un test fonctionnel – est une classe PHP, stockée dans le sous-répertoire #🎜 🎜# de votre Bundle. Si vous suivez ce principe, lors de l'exécution de tous les tests au niveau du programme, exécutez simplement la commande suivante : 🎜#Tests/

PHPunit est configuré via le fichier phpunit.xml.dist dans le répertoire racine de Symfony. phpunit.xml.dist 文件进行配置。

代码覆盖(code coverage)可以通过 —coverage-* 选项来生成。要查看帮助信息,可使用 —help 来显示更多内容。

单元测试 

单元测试是针对单一PHP类的测试,这个类也被称为“单元(unit)”。如果你需要测试你的应用程序层级的整体行为,参考[功能测试] (#catalog2)(Functional Tests)。

编写Symfony单元测试和编写标准的PHPUnit单元测试并无不同。假设,你有一个极其简单的类,类名是 Calculator ,位于app bundle的 Util/ 目录下:

1

为了测试它,创建一个 CalculatorTest 文件到你的bundle的 tests/AppBundle/Util  目录下:

$  phpunit


根据约定, Tests/AppBundle 目录应该复制你的bundle下的单元测试文件所在的目录。因此,如果你要测试的类位于 src/AppBundle/Util 目录下,那么就把测试代码放在 tests/AppBundle/Util/

La couverture du code peut être transmise option —coverage-* générer. Pour afficher les informations d'aide, utilisez —help pour afficher plus de contenu.
#🎜🎜##🎜🎜#

Test unitaire

#🎜🎜#Unit Le test est un test pour une seule classe PHP, également appelée « unité ». Si vous devez tester le comportement global de votre hiérarchie d'applications, consultez Tests fonctionnels (#catalog2). #🎜🎜##🎜🎜#L'écriture de tests unitaires Symfony n'est pas différente de l'écriture de tests unitaires PHPUnit standard. Supposons que vous ayez une classe extrêmement simple nommée Calculator, située dans le répertoire Util/ du bundle d'applications : #🎜🎜#
// src/AppBundle/Util/Calculator.phpnamespace AppBundle\Util; class Calculator{
    public function add($a, $b)
    {
        return $a + $b;
    }}
#🎜🎜#Pour la tester, créez un fichier CalculatorTest dans le répertoire tests/AppBundle/Util de votre bundle :
#🎜🎜#
// tests/AppBundle/Util/CalculatorTest.phpnamespace Tests\AppBundle\Util; use AppBundle\Util\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);
    }}
#🎜🎜#
# 🎜🎜#
#🎜🎜#Selon la convention, le répertoire Tests/AppBundle doit être copié dans le répertoire où se trouvent les fichiers de tests unitaires de votre bundle. Par conséquent, si la classe que vous souhaitez tester se trouve dans le répertoire src/AppBundle/Util, placez le code de test dans le répertoire tests/AppBundle/Util/. #🎜🎜##🎜🎜#


Tout comme votre vraie application – le chargement automatique est automatiquement activé via le fichier bootstrap.php.cache Terminé (cette partie de la configuration est dans le fichier app/phpunit.xml.dist par défaut) bootstrap.php.cache 文件来完成(这部分的配置默认是在app/phpunit.xml.dist文件中)

针对指定文件或目录的测试也很简单:

# run all tests of the application# 运行程序中的所有测试$  phpunit
 # run all tests in the Util directory# 运行指定目录下的所有测试$  phpunit tests/AppBundle/Util
 # run tests for the Calculator class# 仅运行Calculator类的测试$  phpunit tests/AppBundle/Util/CalculatorTest.php
 # run all tests for the entire Bundle# 运行整个bundle的测试$  phpunit tests/AppBundle/

功能测试 

功能测试(Functional tests)检查程序不同层面的整合情况(从路由到视图)。这些层面本身并不因PHPUnit的介入而发生改变,只不过它们有着独特的工作流:

  • 制造一个请求(request);

  • 测试响应(response);

  • 点击一个链接,或提交一个表单;

  • 测试响应;

  • 清除然后重复。

你的第一个功能测试 

功能测试是存放在 Test/AppBundle/Controller 目录下的普通PHP文件。如果要测试由你的 PostController 处理的页面,先创建一个新的PostControllerTest.php文件,并继承一个特殊的 WebTestCase 类。

作为例程,这个测试看起来可能像下面代码:

// tests/AppBundle/Controller/PostControllerTest.phpnamespace 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()
        );
    }}


为了运行上面的功能测试,  WebTestCase 类启动了程序内核。在多数情况下,这是自动完成的。但如果kernel位于非标准目录,你需要调整 phpunit.xml.dist 文件,重新设置 KERNEL_DIR 环境变量为你的kernel目录:


<?xml version="1.0" charset="utf-8" ?><phpunit>
    <php>
        <server name="KERNEL_DIR" value="/path/to/your/app/" />
    </php>
    <!-- ... --></phpunit>

createClient()

Le test pour le fichier ou répertoire spécifié est également très simple :
1
Test fonctionnel < a href="#catalog2" class="headerlink" id="catalog2">¶Les tests fonctionnels (Tests fonctionnels) vérifient l'intégration des différents niveaux du programme ( du parcours à la vue). Ces niveaux eux-mêmes ne changent pas en raison de l'intervention de PHPUnit, mais ils ont des workflows uniques :
  • Votre premier test fonctionnel

    #🎜🎜 #Les tests fonctionnels sont des fichiers PHP ordinaires stockés dans le répertoire Test/AppBundle/Controller. Si vous souhaitez tester les pages gérées par votre PostController, créez d'abord un nouveau fichier PostControllerTest.php et héritez d'une classe spéciale WebTestCase. En routine, ce test pourrait ressembler au code suivant :
    • Faire une demande ;
    • #🎜 ; 🎜#Test de réponse ;
    Cliquez sur un lien ou soumettez un formulaire
    🎜🎜#Test de réponse ;
  • Effacez et répétez.
    $crawler = $client->request('GET', '/post/hello-world');
    #🎜🎜##🎜🎜##🎜🎜#
    # 🎜🎜#Afin d'exécuter le test fonctionnel ci-dessus, la classe WebTestCase démarre le noyau du programme. Dans la plupart des cas, cela se fait automatiquement. Mais si le noyau se trouve dans un répertoire non standard, vous devez ajuster le fichier phpunit.xml.dist et réinitialiser la variable d'environnement KERNEL_DIR dans le répertoire de votre noyau : # 🎜🎜##🎜🎜 ##🎜🎜##🎜🎜##🎜🎜#
    $link = $crawler
        ->filter('a:contains("Greet")') // 选择所有含有"Greet"文本之链接
        ->eq(1) // 结果列表中的第二个
        ->link() // 点击它; $crawler = $client->click($link);
    #🎜🎜#La méthode createClient() renvoie un client, qui peut être utilisé pour simuler un navigateur afin que vous pouvez explorer les pages du site Web :# 🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#
    $form = $crawler->selectButton('submit')->form(); // 设置一些值$form['name'] = 'Lucas';$form['form_name[subject]'] = 'Hey there!'; // 提交表单$crawler = $client->submit($form);
    #🎜🎜##🎜🎜##🎜🎜 ##🎜🎜#
    // Assert that the response matches a given CSS selector.// 断言响应内容匹配到一个指定的CSS拾取器$this->assertGreaterThan(0, $crawler->filter('h1')->count());
    # 🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#

    La méthode request() (voir plus de méthodes de requêterequest()方法 (参考 更多请求方法)返回了一个 Crawler 对象,用于从响应内容中选择元素(select elements),完成点击链接或提交表单这样的动作。

    响应信息必须是XML或HTML文档格式,抓取器(Crawler)才会工作。若需要不带文档格式的纯响应内容(raw content),请使用 $client->getResponse()->getContent()

    需要点击链接时,先用抓取器选择它,可使用XPath表达式或CSS拾取器来完成选 择,然后再使用client行为来点击它:

    $this->assertContains(
        'Hello World',
        $client->getResponse()->getContent());

    提交表单时非常相似:选取一个表单按钮,可选地覆写某些表单项的值,然后提交对应的表单:

    use Symfony\Component\HttpFoundation\Response; // ... // Assert that there is at least one h2 tag// with the class "subtitle"// 断言至少有一个h2标签,其class是subtitle$this->assertGreaterThan(
        0,
        $crawler->filter('h2.subtitle')->count()); // Assert that there are exactly 4 h2 tags on the page// 断言页面有4个h2标签$this->assertCount(4, $crawler->filter('h2')); // Assert that the "Content-Type" header is "application/json"// 断言Content-Type头是application/json$this->assertTrue(
        $client->getResponse()->headers->contains(
            'Content-Type',
            'application/json'
        )); // Assert that the response content contains a string// 断言响应信息中包含一个字符串$this->assertContains('foo', $client->getResponse()->getContent());// ...or matches a regex$this->assertRegExp('/foo(bar)?/', $client->getResponse()->getContent()); // Assert that the response status code is 2xx// 断言响应状态码是2xx$this->assertTrue($client->getResponse()->isSuccessful());// Assert that the response status code is 404// 断言响应状态码是404$this->assertTrue($client->getResponse()->isNotFound());// Assert a specific 200 status code// 断言响应状态码是特殊的200$this->assertEquals(
        200, // or Symfony\Component\HttpFoundation\Response::HTTP_OK
        $client->getResponse()->getStatusCode()); // Assert that the response is a redirect to /demo/contact// 断言响应是一个指向/demo/contact的跳转$this->assertTrue(
        $client->getResponse()->isRedirect('/demo/contact'));// ...or simply check that the response is a redirect to any URL// 或者仅言响应是一个跳转,不管指向的URL是什么$this->assertTrue($client->getResponse()->isRedirect());

    表单也可以处理上传,它还包含了用于填写不同类型的表单字段的方法(例如 select()tick()) renvoie un Crawler, utilisé pour sélectionner des éléments du contenu de la réponse (sélectionner des éléments) pour compléter le lien cliqué Ou des actions comme soumettre un formulaire.

    Les informations de réponse doivent être au format de document XML ou HTML pour que le robot d'exploration fonctionne. Si vous avez besoin de contenu brut sans format de document, veuillez utiliser $client->getResponse()->getContent() .

    Lorsque vous devez cliquer sur un lien, sélectionnez-le d'abord avec un grabber. Vous pouvez utiliser des expressions XPath ou des sélecteurs CSS pour terminer la sélection, puis utiliser le comportement du client pour cliquer dessus :

    1

    C'est très similaire. lors de la soumission d'un formulaire : sélectionnez un bouton Formulaire, écrasez éventuellement les valeurs de certains éléments du formulaire, puis soumettez le formulaire correspondant :

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

    Les formulaires peuvent également gérer les téléchargements et contiennent des méthodes pour remplir différents types de champs de formulaire (tels que select() et tick() ). Pour plus de détails, veuillez vous référer à la section suivante
    Formulaires

    .

    Vous pouvez désormais facilement parcourir votre programme et utiliser des assertions pour tester si vos pages fonctionnent comme prévu. Utilisez un Crawler pour faire agir les assertions sur le DOM.

    request(
        $method,
        $uri,
        array $parameters = array(),
        array $files = array(),
        array $server = array(),
        $content = null,
        $changeHistory = true)

    Ou testez directement le contenu de la réponse, si vous souhaitez simplement affirmer si le contenu contient certains textes, ou simplement savoir que le contenu de la réponse n'est pas au format XML/HTML :

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

    Affirmations utiles

    Afin que vous maîtrisiez les tests le plus rapidement possible, l'exemple suivant répertorie les assertions de test les plus couramment utilisées et utiles :

    $link = $crawler->selectLink('Go elsewhere...')->link();$crawler = $client->click($link); $form = $crawler->selectButton('validate')->form();$crawler = $client->submit($form, array('name' => 'Fabien'));
    Les constantes du code d'état HTTP sont introduites à partir de Symfony 2.4
    Utiliser Test Client
    Le client de test simule un client HTTP, tout comme un navigateur, et peut générer des requêtes pour votre programme Symfony.
    🎜🎜
    // Directly submit a form (but using the Crawler is easier!)// 直接提交表单(但是使用Crawler更容易些)$client->request('POST', '/submit', array('name' => 'Fabien')); // Submit a raw JSON string in the request body// 在请求过程中提交一个JSON原生串$client->request(
        'POST',
        '/submit',
        array(),
        array(),
        array('CONTENT_TYPE' => 'application/json'),
        '{"name":"Fabien"}'); // Form submission with a file upload// 文件上传表单的提交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)); // Perform a DELETE request and pass HTTP headers// 执行一个DELETE请求并传递HTTP头$client->request(
        'DELETE',
        '/post/12',
        array(),
        array(),
        array('PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word'));
    🎜🎜🎜🎜
    1
    🎜🎜🎜🎜🎜La méthode

    request() accepte un paramètre de requête HTTP et un paramètre d'URL, et renvoie une instance de Crawler. request() 方法接受一个HTTP请求方式的参数和一个URL参数,返回一个Crawler实例。

    对于功能测试来说,写死request链接是最佳实践。如果在测试中生成URL时使用Symfony路由,它将无法侦测到针对此URL页面的任何改变,这可能导致用户体验受到冲击。

    以下是更多关于request()方法的例子:

    request()方法的完整用例:

    $client->insulate();

    其中的 server 数组存放了你可能期待使用的PHP超全局变量$_SERVER的原生键值。例如,设置 Content-TypeRefererX-Requested-With (HTTP头)时,你需要传入以下参数(注意用于非标准头的 HTTP_ 前缀):

    $client->back();$client->forward();$client->reload(); // Clears all cookies and the history// 清除所有cookie和历史记录$client->restart();

    使用抓取器来找到响应内容中的DOM元素。这些元素可以被用在点击链接或提交表单等场合:

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

    此处的 click() 方法和 submit() 方法,都会返回一个 crawler 抓取器对象。这些方法是浏览你的程序页面的最佳方式,因为它们帮你做了很多事,像是从表单中侦测HTTP请求方式,或者给你提供一个很好的API用于文件上传。

    在后面的 Crawler 小节中你将学习到更多关于链接Link和表单Form对象的知识。

    request

    Pour les tests fonctionnels, le codage en dur du lien de requête est la meilleure pratique. Si vous utilisez le routage Symfony lors de la génération d'URL dans vos tests, il ne pourra détecter aucune modification apportée à la page URL, ce qui peut compromettre l'expérience utilisateur.


    Voici d'autres exemples de la méthode request() :

    Le cas d'utilisation complet de la méthode
    request() :
    // the HttpKernel request instance// HttpKernel的请求实例$request = $client->getRequest(); // the BrowserKit request instance// 浏览器组件的请求实例$request = $client->getInternalRequest(); // the HttpKernel response instance// HttpKernel的响应实例$response = $client->getResponse(); // the BrowserKit response instance// 浏览器组件的响应实例$response = $client->getInternalResponse(); $crawler = $client->getCrawler();
    Le tableau server stocke les variables super globales PHP que vous pouvez vous attendre à utiliser $_SERVER. Par exemple, lors de la définition de Content-Type, Referer, X-Requested-With (en-tête HTTP), vous devez transmettre les paramètres suivants (notez l'utilisation du préfixe HTTP_ pour les en-têtes non standard) :
    $container = $client->getContainer();$kernel = $client->getKernel();
    1
    Vous en apprendrez davantage dans la section Crawler suivante En savoir plus sur les objets Link et Form. La méthode
    Utilisez un scraper pour trouver les éléments DOM dans le contenu de la réponse. Ces éléments peuvent être utilisés en cliquant sur des liens ou en soumettant des formulaires :
    La méthode click() et la méthode submit() ici renverront toutes deux un crawler Objet robot d'exploration. Ces méthodes constituent le meilleur moyen de parcourir les pages de votre application car elles font beaucoup de choses pour vous, comme détecter les modèles de requête HTTP à partir des formulaires ou vous fournir une API intéressante pour le téléchargement de fichiers.
    🎜request peut également être utilisée pour simuler directement la soumission d'un formulaire ou effectuer des requêtes plus complexes. Quelques exemples utiles : 🎜
    $container = $client->getContainer();
    🎜Un dernier rappel, vous pouvez forcer chaque requête à être exécutée dans son propre processus PHP pour éviter les effets secondaires lorsqu'il y a plusieurs clients dans le même script. 🎜🎜🎜🎜🎜🎜🎜🎜🎜
    // enable the profiler for the very next request// 为接下来的请求开启profiler$client->enableProfiler(); $crawler = $client->request('GET', '/profiler'); // get the profile 得到分析器$profile = $client->getProfile();
    🎜🎜🎜🎜
    1
    🎜🎜🎜🎜🎜

    Navigation

    L'objet client prend en charge de nombreuses opérations dans les navigateurs réels :

    $crawler = $client->followRedirect();

    Utilisation d'objets internes

    getInternalRequest() et getInternalResponse() depuis l'introduction de Symfony 2.3 Be. Si vous utilisez le client pour tester votre programme, vous souhaiterez peut-être utiliser certains objets à l'intérieur du client :

    1

    Vous pouvez également obtenir l'objet lié à la requête la plus récente :

    $client->followRedirects();

    Si votre demande n'est pas isolée Pendant l'exécution, vous pouvez également utiliser Container (conteneur) et Kernel (noyau) : Container (容器)和 Kernel (内核):

    1

    使用容器 

    强烈推荐功能测试只测试响应。但在特定的罕见情况下,你可能要使用内部对象来书写断言。这时,你可以调用Dependency Injection Container(依赖注入容器,即服务容器):

    $client->followRedirects(false);
    $newCrawler = $crawler->filter('input[type=submit]')
        ->last()
        ->parents()
        ->first();

    注意,如果你是把client隔离运行或者使用一个HTTP layer的话,上述功能无效。程序中的可用服务列表,你可通过 debug:container 命令行工具来查看。

    在Symfony2.6之前这个命令是 container:debug

    如果你需要检查的信息在分析器(profiler)中可用,那么应使用profiler来替代container。

    使用分析数据 

    每一次请求,你都可以借助Symfony分析器(profiler)来收集关于该请求在内部被处理的有关信息。例如,分析器常被用于验证指定页面在加载过程中的数据库查询次数是否小于给定值。

    为了得到最近一次请求的Profiler,按下例操作:

    $crawler
        ->filter('h1')
        ->reduce(function ($node, $i) {
            if (!$node->getAttribute('class')) {
                return false;
            }
        })
        ->first();

    在测试中使用分析器的某些细节,请参阅 如何在功能测试中使用分析器 一文。

    重定向 

    当一个请求返回的是重定向响应时,client并不自动跟进。你可以检测该响应信息,然后通过 followRedirect()

    // 返回第一个节点的属性值$crawler->attr('class'); // 返回第一个节点的节点文本$crawler->text(); // Extracts an array of attributes for all nodes// (_text returns the node value)// returns an array for each element in crawler,// each with the value and href// 提取一个由所有节点的属性组成的数组// (_text返回节点值)// 返回一个由抓取器中的每一个元素所组成的数组// 每个元素有value和href$info = $crawler->extract(array('_text', 'href')); // Executes a lambda for each node and return an array of results// 对每个节点执行一次lambda函数(即匿名函数),最后返回结果数组$data = $crawler->each(function ($node, $i) {
        return $node->attr('href');});

    Utiliser le conteneur
    Il est fortement recommandé que les tests fonctionnels testent uniquement la réponse. Mais dans certains cas rares, vous souhaiterez peut-être utiliser des objets internes pour écrire des assertions. À ce stade, vous pouvez appeler Dependency Injection Container (conteneur d'injection de dépendances, c'est-à-dire conteneur de services) :
    1
    $crawler->selectLink('Click here');
    🎜🎜🎜🎜🎜🎜🎜🎜Notez que si vous exécutez le client isolé Ou si vous utilisez une couche HTTP, les fonctions ci-dessus ne sont pas valides. Vous pouvez afficher la liste des services disponibles dans le programme via l'outil de ligne de commande debug:container. 🎜🎜🎜Avant Symfony2.6, cette commande était container:debug. 🎜🎜

    Si vous avez besoin que le client suive automatiquement toutes les redirections, vous pouvez le forcer à implémenter, utilisez la méthode followRedirects() : followRedirects() 方法:

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

    false 传给 followRedirects()

    $form = $buttonCrawlerNode->form(array(
        'name'              => 'Fabien',
        'my_form[subject]'  => 'Symfony rocks!',));
    1
    🎜🎜 Passez false à la méthode followRedirects(), et la redirection ne sera plus suivie : 🎜🎜🎜🎜🎜🎜🎜🎜
    $form = $buttonCrawlerNode->form(array(), 'DELETE');
    🎜🎜 🎜🎜
    1
    🎜🎜🎜🎜🎜

    Crawler

    Chaque fois que vous faites une demande via le client, une instance Crawler est renvoyée. Les Scrapers vous permettent de parcourir des documents HTML, de récupérer des nœuds DOM et de trouver des liens et des formulaires.

    Traversing

    Tout comme JQuery, le robot dispose de différentes méthodes pour parcourir le DOM d'un document HTML/XML. Par exemple, la méthode suivante recherche tous les éléments input[type=submit], sélectionne le dernier de la page, puis sélectionne son élément parent adjacent : input[type=submit] 元素,并选择页面中的最后一个,然后选择它的临近父元素:

    $client->submit($form);

    还有很多其他方法可以利用:

    • filter('h1.title')
    • 匹配CSS拾取器的所有节点。
    • filterXpath('h1')
    • 匹配XPath expression(表达式)的所有节点。
    • eq(1)
    • 指定索引的节点。
    • first()
    • 第一个节点。
    • last()
    • 最后一个节点。
    • siblings()
    • Siblings。
    • nextAll()
    • 后续所有siblings。
    • previousAll()
    • 之前所有siblings。
    • parents()
    • 返回所有父节点。
    • children()
    • 返回所有子节点。
    • reduce($lambda)
    • 匿名函数$lambda不返回false时的所有节点。

    由于上述每个方法都返回一个 Crawler 抓取器对象,你可以通过对各方法的链式调用来减少节点拾取过程的代码:

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

    可以使用 count() 函数来得到存储在一个Crawler中的节点数量: count($crawler)

    提取信息 

    抓取器可以从节点中提到信息:

    // 改变某个字段的值/Change the value of a field$form['name'] = 'Fabien';$form['my_form[subject]'] = 'Symfony rocks!';

    链接 

    为了选择链接,你可以使用上述遍历方法,或者使用更方便的 selectLink()

    // 选取一个option单选或radio单选$form['country']->select('France'); // 选取一个checkbox$form['like_symfony']->tick(); // 上传一个文件$form['photo']->upload('/path/to/lucas.jpg');

    Il existe de nombreuses autres méthodes qui peuvent être utilisé :
    • filter('h1.title')
    • Tous les nœuds correspondant aux sélecteurs CSS .
    • filterXpath('h1')
    • Tous les nœuds correspondant à l'expression XPath (expression).
    • eq(1)
    • Le nœud spécifiant l'index.
    • first()
    • Le premier nœud.
    • last()
    • Le dernier nœud.
    • frères et sœurs()
    • Frères et sœurs.
    • nextAll()
    • Tous les frères et sœurs suivants.
    • previousAll()
    • Tous les frères et sœurs précédents.
    • parents()
    • Renvoie tous les nœuds parents.
    • children()
    • Renvoie tous les nœuds enfants.
    • reduce($lambda)
    • Tous les nœuds lorsque la fonction anonyme $lambda ne renvoie pas false.
    Étant donné que chacune des méthodes ci-dessus renvoie un objet grabber Crawler, vous pouvez réduire le code du processus de sélection de nœud en enchaînant les appels à chaque méthode :
    // Get the form. 取得表单$form = $crawler->filter('button')->form(); // Get the raw values. 取得原始数值$values = $form->getPhpValues(); // Add fields to the raw values. 给原始数组添加新字段$values['task']['tag'][0]['name'] = 'foo';$values['task']['tag'][1]['name'] = 'bar'; // Submit the form with the existing and new values.// 提交表单,包括既有值,以及新值$crawler = $this->client->request($form->getMethod(), $form->getUri(), $values,
        $form->getPhpFiles()); // The 2 tags have been added to the collection.// 2个新标签被添加到collection中$this->assertEquals(2, $crawler->filter('ul.tags > li')->count());
    < div class="admonition admonition-tip">Le robot peut extraire des informations des nœuds :
    // Get the values of the form. 取得表单数据$values = $form->getPhpValues(); // Remove the first tag. 移除第一个标签unset($values['task']['tags'][0]); // Submit the data. 提交数据$crawler = $client->request($form->getMethod(), $form->getUri(),
        $values, $form->getPhpFiles()); // The tag has been removed. 标签已被移除$this->assertEquals(0, $crawler->filter('ul.tags > li')->count());
    Vous pouvez utiliser la fonction count() pour obtenir le nombre de nœuds stockés dans un Crawler : count($crawler)
    Extraire des informations
    Lien ¶🎜
    🎜🎜Pour sélectionner un lien, vous pouvez utiliser la méthode de traversée ci-dessus, ou utiliser la méthode de raccourci selectLink() plus pratique :🎜 🎜🎜🎜🎜🎜🎜🎜
    PHP:// app/config/config_test.php // ...$container->loadFromExtension('swiftmailer', array(
        'disable_delivery' => true,));
    🎜🎜🎜🎜
    XML:<!-- 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>
    🎜🎜🎜🎜🎜

    Cela vous permet de sélectionner tous les liens qui contiennent le texte donné, ou les images cliquables dont les attributs alt contiennent le texte donné. Semblable à d'autres méthodes de filtrage, elle renvoie également un objet Crawler. alt 属性中包含了给定文本。和其他的过滤方法类似,它也是返回一个 Crawler 对象。

    一旦你选中了一个链接(link),你就可以使用一个特殊的链接对象( link  object),它是一个专门用来处理链接的方法(类似 getMethod()getUri() 这种,都属于帮助方法/helpful method)。要点击链接,使用Client的 click() 方法,并把链接对象传进去:

    YAML:# app/config/config_test.yml # ...swiftmailer:
        disable_delivery: true

    表单 

    表单可以通过它们的按钮被选择,而按钮可以用selectButton()方法来选择,正如选择链接一样:

    $client = static::createClient(array(
        'environment' => 'my_test_env',
        'debug'       => false,));
    $client = static::createClient(array(), array(
        'HTTP_HOST'       => 'en.example.com',
        'HTTP_USER_AGENT' => 'MySuperBrowser/1.0',));

    注意你选择的是表单的按钮而不是表单本身,因为表单可以有多个按钮。如果你使用遍历API,记住必须要找到一个按钮。

    selectButton() 方法可以选中 button (按钮)标签,以及submit(提交)所在的标签(即 input 标签)。它使用按钮的几个部分来找到它们:

    • value 属性值(The value attribute value)

    • 图片按钮的 id 属性值或 alt 属性值(The id or alt attribute value for images)

    • button 标签的 id 属性值或 name 属性值(The id or name attribute value for button tags)

    当你有了一个含有button的crawler之后,调用 form() 方法即可得到拥有这个button节点的form实例。

    $client->request('GET', '/', array(), array(), array(
        'HTTP_HOST'       => 'en.example.com',
        'HTTP_USER_AGENT' => 'MySuperBrowser/1.0',));
    <!-- app/phpunit.xml.dist --><phpunit>
        <!-- ... -->
        <testsuites>
            <testsuite name="Project Test Suite">
                <directory>../src/*/*Bundle/Tests</directory>
                <directory>../src/*/Bundle/*Bundle/Tests</directory>
                <directory>../src/*Bundle/Tests</directory>
            </testsuite>
        </testsuites>
        <!-- ... --></phpunit>

    当调用 form()

    Une fois que vous avez sélectionné un lien, vous pouvez utiliser un objet lien spécial (objet link), qui est une méthode spécifiquement utilisée pour gérer les liens (similaire à getMethod() ou getUri() sont toutes des méthodes d'assistance/méthodes utiles). Pour cliquer sur un lien, utilisez la méthode click() du Client et transmettez l'objet lien dans :

    <!-- app/phpunit.xml.dist --><phpunit>
        <!-- ... -->
        <testsuites>
            <testsuite name="Project Test Suite">
                <!-- ... - - ->            <directory>../lib/tests</directory>        </testsuite>    </testsuites>    <!-- ... - - -></phpunit>

    Form

    Les formulaires peuvent être sélectionnés via leurs boutons, et les boutons peuvent être sélectionnés à l'aide de la méthode selectButton(), tout comme la sélection de liens :
    <!-- app/phpunit.xml.dist --><phpunit>
        <!-- ... -->
        <filter>
            <whitelist>
                <!-- ... -->
                <directory>../lib</directory>
                <exclude>
                    <!-- ... -->
                    <directory>../lib/tests</directory>
                </exclude>
            </whitelist>
        </filter>
        <!-- ... - - -></phpunit>
    rrreee
    🎜🎜🎜
    🎜Notez que vous sélectionnez le bouton du formulaire et non le formulaire lui-même, car le formulaire peut contenir plusieurs boutons. Si vous utilisez l'API de traversée, n'oubliez pas que vous devez trouver un bouton. 🎜🎜🎜🎜La méthode selectButton() peut sélectionner l'étiquette button (bouton) et l'étiquette où se trouve submit (submit) (c'est-à-dire input étiquette) . Il utilise plusieurs parties du bouton pour les retrouver : 🎜
    • 🎜value La valeur de l'attribut value 🎜
    • 🎜Le de l'identifiant du bouton image< /code> valeur d'attribut ou valeur d'attribut alt (la valeur d'attribut id ou alt pour les images)🎜
    • 🎜button de la balise id< Valeur d'attribut /code> ou valeur d'attribut name (la valeur d'attribut id ou name pour les balises de bouton)🎜
    🎜Lorsque vous avez un robot contenant un bouton, appelez le form() pour obtenir l'instance de formulaire qui possède ce nœud de bouton. Lors de l'appel de la méthode form(), vous pouvez également transmettre un tableau contenant les valeurs des champs du formulaire. in, pour remplacer la valeur par défaut : 🎜rrreee🎜 Lorsque vous souhaitez simuler une méthode de soumission de formulaire HTTP spécifique, transmettez-la comme deuxième paramètre : 🎜🎜🎜🎜🎜🎜🎜🎜🎜rrreee🎜🎜🎜🎜rrreee🎜🎜 🎜🎜🎜

    Le client est responsable de la soumission de l'instance de formulaire :

    rrreee
    rrreee

    La valeur du champ peut être passée au deuxième paramètre de la méthode submit() :

    rrreee

    Pour des situations plus complexes, l'instance du formulaire peut être utilisée comme un tableau pour définir la valeur correspondant à chaque champ :

    rrreee

    Il existe également une API utile pour gérer les valeurs de champ en fonction de leurs types :

    rrreee

    Si vous souhaitez délibérément sélectionner des valeurs de sélection/radio "invalides", reportez-vous à Sélectionner des valeurs de choix invalides .

    Vous pouvez obtenir les valeurs des champs de formulaire qui sont sur le point d'être soumises en appelant la méthode getValues() de l'objet Form. Les fichiers téléchargés peuvent également être obtenus à partir d'un tableau détaché renvoyé par la méthode getFiles(). Les méthodes getPhpValues() et getPhpFiles() peuvent également renvoyer des champs soumis, mais au format PHP (elle prend la clé entre crochets – comme my_form[subject ] – converti en tableau PHP). getValues() 方法即可。已上传的文件也可以从一个分离出来的数组得到,这个数组由 getFiles() 方法返回。 getPhpValues() 以及 getPhpFiles() 方法同样可以返回已经提交的字段,只不过是PHP格式的(它把带有方括号的键 – 比如 my_form[subject]  – 给转换成PHP数组)。

    添加或删除表单到Collection 

    如果你使用了 Collection of Forms(表单集合),你不能对既有表单添加一个 $form['task[tags][0][name]'] = 'foo 字段。这会导致一个 Unreachable field "…" 错误。因为 $form 只能被用于设置现有的字段。为了添加一个新字段,你不得不把值添加到一个原始数组中:

    rrreee

    这里的 task[tags][0][name] 就是由JavaScript创建的字段的名字。

    你可以移除一个既有字段,比如一个标签(tag):

    rrreee

    配置测试 

    功能测试所用到的Client创建了一个Kernel,用于在一个特殊的 test 测试环境中运行。由于Symfony在测试时加载的是 app/config/config_test.yml

    Ajoutez ou supprimez des formulaires à la collection

    , vous ne pouvez pas ajouter un champ $form['task[tags][0][name]'] = 'foo. Cela entraîne une erreur Champ inaccessible "…". Parce que $form ne peut être utilisé que pour définir des champs existants. Pour ajouter un nouveau champ, vous devez ajouter la valeur à un tableau primitif : 🎜rrreee🎜 Ici task[tags][0][name] est le nom du champ créé par JavaScript. 🎜🎜🎜Vous pouvez supprimer un champ existant, comme une balise : 🎜rrreee🎜Test de configuration ¶🎜🎜🎜🎜Test fonctionnel Le Client utilisé crée un noyau pour s'exécuter dans un environnement de test spécial test. Étant donné que Symfony charge app/config/config_test.yml lors des tests, vous pouvez ajuster tous les paramètres « au niveau du programme » utilisés pour les tests. 🎜🎜Par exemple, Swift Mailer par défaut est configuré pour ne pas envoyer d'e-mails dans un environnement de test. Les options pertinentes dans le fichier de configuration sont définies comme ceci : 🎜rrreeerrreee🎜rrreee🎜

    Vous pouvez également utiliser un environnement complètement différent, ou remplacer le mode de débogage par défaut ( true ) en passant les options appropriées à la méthode createClient() : true ),通过把相关选项传给 createClient() 方法即可:

    rrreee

    如果你的程序需要通过一些HTTP头才能运转,把它们传给createClient()方法的第二个参数:

    rrreee

    你也可以在每一个request基本过程中覆写HTTP header:

    rrreee

    client在 test 测试环境下是容器中的可用服务(或者无论什么环境,只要 framework.test选项被开启)。这意味着只要需要,你可以覆写整个client服务。


    PHPUnit配置 

    每一个程序,有它自己的PHPUnit配置,就存在 app/phpunit.xml.dist 文件中。你可以编辑这个文件,改变默认值,或创建一个仅供你本地机器设定测试选项的 app/phpunit.xml 文件。

    app/phpunit.xml.dist 文件存在你的代码宝库中并且忽略 app/phpunit.xmlrrreee

    Si votre Le programme nécessite certains en-têtes HTTP pour s'exécuter, transmettez-les au deuxième paramètre de la méthode createClient() :
    rrreee

    Vous pouvez également remplacer l'en-tête HTTP dans chaque processus de requête : rrreee

    client est un service disponible dans le conteneur dans l'environnement de test test (ou quel que soit l'environnement, à condition que framework.test est activée). Cela signifie que vous pouvez remplacer l'intégralité du service client chaque fois que cela est nécessaire.


    Configuration PHPUnit

    Chaque programme a sa propre configuration PHPUnit, existe juste dans le Fichier app/phpunit.xml.dist. Vous pouvez modifier ce fichier pour modifier les valeurs par défaut ou créer un fichier app/phpunit.xml qui définit les options de test uniquement pour votre ordinateur local.

    Enregistrez le fichier app/phpunit.xml.dist dans votre référentiel et ignorez le Fichier app/phpunit.xml.

    🎜Par défaut, seuls les tests stockés dans votre bundle personnalisé sous le répertoire standard (src/🎜/🎜Bundle/Tests, src/🎜/Bundle/🎜Bundle/Tests, src/*Bundle/Tests) peuvent être exécutés par le commande phpunit. Ceci est déjà configuré dans le fichier app/phpunit.xml.dist : 🎜rrreee🎜 Mais vous pouvez facilement ajouter plus de répertoires. Par exemple, la configuration suivante ajoute des tests dans le répertoire personnalisé lib/tests :🎜🎜rrreee🎜Afin d'inclure d'autres répertoires dans la couverture de code, vous devez également ajouter un 🎜extrait de code :🎜🎜🎜rrreee🎜