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/
—coverage-* code> 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éeCalculator
, 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); }}#🎜🎜#
# 🎜🎜#
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()
1
| Cliquez sur un lien ou soumettez un formulaire 🎜🎜#Test de réponse ; Effacez et répétez. |
$crawler = $client->request('GET', '/post/hello-world');#🎜🎜##🎜🎜##🎜🎜#
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.
$client->getResponse()->getContent()
. 1C'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');
select()
et tick() code> ). Pour plus de détails, veuillez vous référer à la section suivante 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页面的任何改变,这可能导致用户体验受到冲击。
使用抓取器来找到响应内容中的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.