특정 순서로 PHPUnit 테스트 실행
-
08-06-2019 - |
문제
내부에서 테스트를 받을 수 있는 방법이 있나요? TestCase
특정 순서로 실행하려면?예를 들어, 객체의 수명 주기를 생성에서 사용, 폐기까지 분리하고 싶지만 다른 테스트를 실행하기 전에 먼저 객체가 설정되었는지 확인해야 합니다.
해결책
테스트에 디자인 문제가 있을 수 있습니다.
일반적으로 각 테스트는 다른 테스트에 의존해서는 안 되므로 순서에 관계없이 실행될 수 있습니다.
각 테스트는 실행하는 데 필요한 모든 것을 인스턴스화하고 파괴해야 합니다. 이는 완벽한 접근 방식이 될 것입니다. 테스트 간에 개체와 상태를 공유해서는 안 됩니다.
N 테스트에 동일한 객체가 필요한 이유에 대해 더 구체적으로 설명할 수 있습니까?
다른 팁
PHPUnit은 다음을 통해 테스트 종속성을 지원합니다. @의존 주석.
다음은 종속성을 충족하는 순서로 테스트가 실행되는 문서의 예입니다. 각 종속 테스트는 인수를 다음 테스트에 전달합니다.
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);
}
}
그러나 해결되지 않은 종속성이 있는 테스트는 ~ 아니다 실행됩니다(이렇게 하면 실패한 테스트에 빠르게 주의를 끌 수 있으므로 바람직합니다).따라서 종속성을 사용할 때는 세심한 주의를 기울이는 것이 중요합니다.
이에 대한 정답은 테스트에 적합한 구성 파일입니다.나는 동일한 문제가 있었고 필요한 테스트 파일 순서로 테스트 스위트를 생성하여 문제를 해결했습니다.
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에서는 종속 테스트 사례를 지정하고 종속 테스트 사례 간에 인수를 전달할 수 있는 '@dependents' 주석을 사용할 수 있습니다.
내 생각에는 특정 리소스의 생성 및 삭제를 테스트해야 하는 다음 시나리오를 생각해 보세요.
처음에는 두 가지 방법이 있었습니다.testCreateResource 및 b.테스트파괴자원
ㅏ.테스트생성자원
<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
?>
비.테스트파괴자원
<?php
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
testDestroyResource는 testCreateResource에 의존하기 때문에 이것은 나쁜 생각이라고 생각합니다.그리고 더 나은 연습은 다음과 같습니다
ㅏ.테스트생성자원
<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
$app->deleteResource('resource');
?>
비.테스트파괴자원
<?php
$app->createResource('resource');
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
대체 솔루션:재사용 가능한 요소를 생성하려면 테스트에 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, '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();
}
- 이러한 방식으로 테스트의 계층 구조를 구축할 수 있습니다.
- 각 테스트 케이스가 서로 완전히 분리되어 있다는 속성을 강철로 유지할 수 있습니다(각 테스트 후에 DB를 정리하는 경우).
- 그리고 가장 중요한 점은 예를 들어 향후 로그인 변경 방법이 LoginTest 클래스만 수정하고 다른 테스트에서는 올바른 로그인 부분이 필요하지 않은 경우(LoginTest 업데이트 후에 작동해야 함) :)
테스트를 실행하면 스크립트가 시작부터 DB 광고를 정리합니다.위에서는 내 SeleniumClearTestCase
클래스(저는 거기에 스크린샷()과 다른 멋진 기능을 만듭니다)은 다음의 확장입니다. MigrationToSelenium2
(github에서 seleniumIDE + ff 플러그인 "Selenium IDE:내 클래스 LaravelTestCase(Illuminate\Foundation esting estCase의 복사본이지만 PHPUnit_Framework_TestCase를 확장하지 않음)의 확장인 PHP Formatters")는 테스트가 끝날 때 DB를 정리할 때 eloquent에 액세스할 수 있도록 laravel을 설정합니다. PHPUnit_Extensions_Selenium2TestCase의 확장입니다.laravel eloquent를 설정하려면 SeleniumClearTestCase 함수 createApplication(에서 호출됨)에도 있습니다. setUp
, 나는 이 함수를 laral test/TestCase에서 가져옵니다)
테스트를 특정 순서로 실행해야 한다면 실제로 문제가 있는 것입니다.각 테스트는 다른 테스트와 완전히 독립적이어야 합니다.결함 위치 파악에 도움이 되며 반복 가능한(따라서 디버깅 가능한) 결과를 얻을 수 있습니다.
점검 이 장소 이러한 종류의 문제를 피하는 방식으로 테스트를 고려하는 방법에 대한 수많은 아이디어/정보를 제공합니다.