특정 순서로 PHPUnit 테스트 실행
내부에서 테스트를 TestCase
특정 순서로 실행 하는 방법이 있습니까? 예를 들어, 객체의 수명주기를 생성에서 사용, 소멸까지 분리하고 싶지만 다른 테스트를 실행하기 전에 먼저 객체가 설정되어 있는지 확인해야합니다.
테스트에 디자인 문제가있을 수 있습니다.
일반적으로 각 테스트는 다른 테스트에 의존하지 않아야하므로 순서에 관계없이 실행할 수 있습니다.
각 테스트는 실행에 필요한 모든 것을 인스턴스화하고 파괴해야합니다. 이것이 완벽한 접근 방식입니다. 테스트간에 객체와 상태를 공유해서는 안됩니다.
N 개의 테스트에 동일한 객체가 필요한 이유를 더 구체적으로 설명 할 수 있습니까?
PHPUnit은 @depends 주석을 통해 테스트 종속성을 지원합니다 .
다음은 각 종속 테스트가 다음 인수를 전달하면서 종속성을 충족하는 순서로 테스트가 실행되는 문서의 예입니다.
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);
}
}
그러나 해결되지 않은 종속성이있는 테스트는 실행 되지 않는다는 점에 유의하는 것이 중요합니다 (실패한 테스트에 빠르게주의를 기울이기 때문에 바람직 함). 따라서 종속성을 사용할 때 세심한주의를 기울이는 것이 중요합니다.
이에 대한 정답은 테스트를위한 적절한 구성 파일입니다. 나는 동일한 문제가 있었고 필요한 테스트 파일 순서로 testsuite를 만들어 수정했습니다.
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>
테스트에서 다양한 도우미 개체 및 설정을 공유하도록하려면 setUp()
, tearDown()
을 사용 하여 sharedFixture
속성 에 추가 할 수 있습니다 .
PHPUnit에서는 종속 테스트 케이스를 지정하고 종속 테스트 케이스간에 인수를 전달할 수있는 '@depends'주석을 사용할 수 있습니다.
내 견해로는 특정 리소스의 생성 및 삭제를 테스트해야하는 다음 시나리오를 사용합니다.
처음에는 두 가지 방법이있었습니다. testCreateResource 및 b. testDestroyResource
ㅏ. testCreateResource
<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
?>
비. testDestroyResource
<?php
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
testDestroyResource가 testCreateResource에 의존하기 때문에 이것은 나쁜 생각이라고 생각합니다. 그리고 더 나은 방법은
ㅏ. testCreateResource
<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
$app->deleteResource('resource');
?>
비. testDestroyResource
<?php
$app->createResource('resource');
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
대체 솔루션 : 테스트에서 static (!) 함수를 사용하여 재사용 가능한 요소를 만듭니다. 예를 들어 (셀레늄 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, 'john.smith@gmail.com', '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]"));
}
}
좋아, 이제 다른 테스트에서 재사용 가능한 요소를 사용할 수 있습니다. :) 예를 들어 :
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, 'paris@gmail.com','hilton');
$t->screenshot(); // take some photos :)
$t->assertEquals($title, $t->getText('...'));
}
public static function cleanAddBlogTitle() {
$lastTitle = BlogTitlesHistory::orderBy('id')->first();
$lastTitle->delete();
}
- 이러한 방식으로 테스트 계층 구조를 구축 할 수 있습니다.
- 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) :)
When I run test my script clean up db ad the begining. Above I use my SeleniumClearTestCase
class (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)
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 site for a whole load of ideas / information, about how to factor your tests in a manner where you avoid these kinds of issues.
ReferenceURL : https://stackoverflow.com/questions/10228/run-phpunit-tests-in-certain-order
'development' 카테고리의 다른 글
목록에서 중복을 제거하는 방법은 무엇입니까? (0) | 2020.12.31 |
---|---|
UIPageViewController에서 점 숨기기 (0) | 2020.12.31 |
내부에 2 색 입자가있는 수정 구슬을 그리는 방법 (0) | 2020.12.31 |
Swift : 레이블 또는 textView에 HTML 데이터 표시 (0) | 2020.12.31 |
하나의 IPython 노트북 셀에 여러 이미지를 표시 하시겠습니까? (0) | 2020.12.31 |