php 按特定顺序运行 PHPUnit 测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10228/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Run PHPUnit Tests in Certain Order
提问by dragonmantank
Is there a way to get the tests inside of a TestCaseto run in a certain order? For example, I want to separate the life cycle of an object from creation to use to destruction but I need to make sure that the object is set up first before I run the other tests.
有没有办法让 a 中的测试TestCase按特定顺序运行?例如,我想将对象的生命周期从创建到使用再到销毁分开,但我需要确保在运行其他测试之前先设置对象。
采纳答案by Fabio Gomes
Maybe there is a design problem in your tests.
也许您的测试中存在设计问题。
Usually each test must not depend on any other tests, so they can run in any order.
通常每个测试不得依赖于任何其他测试,因此它们可以按任何顺序运行。
Each test needs to instantiate and destroy everything it needs to run, that would be the perfect approach, you should never share objects and states between tests.
每个测试都需要实例化和销毁它运行所需的一切,这将是完美的方法,你不应该在测试之间共享对象和状态。
Can you be more specific about why you need the same object for N tests?
您能否更具体地说明为什么 N 个测试需要相同的对象?
回答by mjs
PHPUnit supports test dependencies via the @dependsannotation.
PHPUnit 通过@depends注解支持测试依赖。
Here is an example from the documentation where tests will be run in an order that satisfies dependencies, with each dependent test passing an argument to the next:
这是文档中的一个示例,其中测试将按照满足依赖关系的顺序运行,每个依赖测试都将参数传递给下一个:
class StackTest extends PHPUnit_Framework_TestCase
{
public function testEmpty()
{
$stack = array();
$this->assertEmpty($stack);
return $stack;
}
/**
* @depends testEmpty
*/
public function testPush(array $stack)
{
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertNotEmpty($stack);
return $stack;
}
/**
* @depends testPush
*/
public function testPop(array $stack)
{
$this->assertEquals('foo', array_pop($stack));
$this->assertEmpty($stack);
}
}
However, it's important to note that tests with unresolved dependencies will notbe executed (desirable, as this brings attention quickly to the failing test). So, it's important to pay close attention when using dependencies.
但是,重要的是要注意具有未解析依赖项的测试将不会被执行(这是可取的,因为这会很快引起对失败测试的关注)。因此,在使用依赖项时密切注意是很重要的。
回答by Gino Pane
The correct answer for this is a proper configuration file for tests. I had the same problem and fixed it by creating testsuite with necessary test files order:
正确的答案是正确的测试配置文件。我遇到了同样的问题,并通过使用必要的测试文件顺序创建测试套件来修复它:
phpunit.xml:
<phpunit
colors="true"
bootstrap="./tests/bootstrap.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
strict="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
>
<testsuites>
<testsuite name="Your tests">
<file>file1</file> //this will be run before file2
<file>file2</file> //this depends on file1
</testsuite>
</testsuites>
</phpunit>
回答by Gary Richardson
If you want your tests to share various helper objects and settings, you can use setUp(), tearDown()to add to the sharedFixtureproperty.
如果您希望您的测试共享各种辅助对象和设置,您可以使用setUp(),tearDown()添加到sharedFixture属性中。
回答by saleem badreddine
PHPUnit allows the use of '@depends' annotation which specifies dependent test cases and allows passing arguments between dependent test cases.
PHPUnit 允许使用“@depends”注释,它指定依赖测试用例并允许在依赖测试用例之间传递参数。
回答by bibstha
In my view, take the following scenario where I need to test creation and destroying of a particular resource.
在我看来,采用以下场景,我需要测试特定资源的创建和销毁。
Initially I had two methods, a. testCreateResource and b. testDestroyResource
最初我有两种方法,一个。testCreateResource 和 b。测试销毁资源
a. testCreateResource
一种。测试创建资源
<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
?>
b. testDestroyResource
湾 测试销毁资源
<?php
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
I think this is a bad idea, as testDestroyResource depends upon testCreateResource. And a better practice would be to do
我认为这是一个坏主意,因为 testDestroyResource 依赖于 testCreateResource。更好的做法是做
a. testCreateResource
一种。测试创建资源
<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
$app->deleteResource('resource');
?>
b. testDestroyResource
湾 测试销毁资源
<?php
$app->createResource('resource');
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
回答by Kamil Kie?czewski
Alternative solution: Use static(!) functions in your tests to create reusable elements. For instance (I use selenium IDE to record tests and phpunit-selenium (github) to run test inside browser)
替代解决方案:在测试中使用 static(!) 函数来创建可重用元素。例如(我使用 selenium IDE 来记录测试和 phpunit-selenium (github) 在浏览器中运行测试)
class LoginTest extends SeleniumClearTestCase
{
public function testAdminLogin()
{
self::adminLogin($this);
}
public function testLogout()
{
self::adminLogin($this);
self::logout($this);
}
public static function adminLogin($t)
{
self::login($t, '[email protected]', 'pAs$w0rd');
$t->assertEquals('John Smith', $t->getText('css=span.hidden-xs'));
}
// @source LoginTest.se
public static function login($t, $login, $pass)
{
$t->open('/');
$t->click("xpath=(//a[contains(text(),'Log In')])[2]");
$t->waitForPageToLoad('30000');
$t->type('name=email', $login);
$t->type('name=password', $pass);
$t->click("//button[@type='submit']");
$t->waitForPageToLoad('30000');
}
// @source LogoutTest.se
public static function logout($t)
{
$t->click('css=span.hidden-xs');
$t->click('link=Logout');
$t->waitForPageToLoad('30000');
$t->assertEquals('PANEL', $t->getText("xpath=(//a[contains(text(),'Panel')])[2]"));
}
}
Ok, and now, i can use this reusable elements in other test :) For instance:
好的,现在,我可以在其他测试中使用这个可重用元素:) 例如:
class ChangeBlogTitleTest extends SeleniumClearTestCase
{
public function testAddBlogTitle()
{
self::addBlogTitle($this,'I like my boobies');
self::cleanAddBlogTitle();
}
public static function addBlogTitle($t,$title) {
LoginTest::adminLogin($t);
$t->click('link=ChangeTitle');
...
$t->type('name=blog-title', $title);
LoginTest::logout($t);
LoginTest::login($t, '[email protected]','hilton');
$t->screenshot(); // take some photos :)
$t->assertEquals($title, $t->getText('...'));
}
public static function cleanAddBlogTitle() {
$lastTitle = BlogTitlesHistory::orderBy('id')->first();
$lastTitle->delete();
}
- In this way, you can build hierarchy of you tests.
- You can steel keep property that each test case is totaly separate from other (if you clean DB after each test).
- And most important, if for instance, the way of login change in future, you only modify LoginTest class, and you don'n need correct login part in other tests (they should work after update LoginTest) :)
- 通过这种方式,您可以构建测试的层次结构。
- 您可以保留每个测试用例与其他测试用例完全分开的属性(如果您在每次测试后清理数据库)。
- 最重要的是,例如,如果以后登录方式发生变化,您只需修改 LoginTest 类,而其他测试中不需要正确的登录部分(它们应该在更新 LoginTest 后工作):)
When I run test my script clean up db ad the begining. Above I use my SeleniumClearTestCaseclass (I make screenshot() and other nice functions there) it is extension of MigrationToSelenium2(from github, to port recorded tests in firefox using seleniumIDE + ff plugin "Selenium IDE: PHP Formatters" ) which is extension of my class LaravelTestCase (it is copy of Illuminate\Foundation\Testing\TestCase but not extends PHPUnit_Framework_TestCase) which setup laravel to have access to eloquent when we want to clean DB at the end of test) which is extension of PHPUnit_Extensions_Selenium2TestCase. To set up laravel eloquent I have also in SeleniumClearTestCase function createApplication (which is called at setUp, and I take this function from laral test/TestCase)
当我运行测试时,我的脚本开始清理 db ad。上面我使用我的SeleniumClearTestCase类(我在那里制作了屏幕截图()和其他不错的函数)它是MigrationToSelenium2(从 github,到使用 seleniumIDE + ff 插件“Selenium IDE:PHP Formatters”在 firefox 中移植记录的测试)的扩展,它是我的类的扩展LaravelTestCase(它是 Illuminate\Foundation\Testing\TestCase 的副本,但不是扩展 PHPUnit_Framework_TestCase),当我们想在测试结束时清理数据库时,它设置 Laravel 可以访问 eloquent)它是 PHPUnit_Extensions_Selenium2TestCase 的扩展。为了设置 laravel eloquent 我也在 SeleniumClearTestCase 函数 createApplication (它被调用setUp,我从 laral test/TestCase 获取这个函数)
回答by jkp
There really is a problem with your tests if they need to run in a certain order. Each test should be totally independent of the others: it helps you with defect localization, and allows you to get repeatable (and therefore debuggable) results.
如果您的测试需要按特定顺序运行,则确实存在问题。每个测试都应该完全独立于其他测试:它可以帮助您定位缺陷,并允许您获得可重复(因此可调试)的结果。
Checkout this sitefor a whole load of ideas / information, about how to factor your tests in a manner where you avoid these kinds of issues.
查看此站点以获取大量想法/信息,了解如何以避免此类问题的方式分解测试。

