이 패키지는 Swoole을 사용하여 시간/IO 관련 단위 테스트(예: 절전 함수 호출, 데이터베이스 쿼리, API 호출 등)를 더 빠르게 실행하는 데 도움이 됩니다.
패키지 집합을 사용하면 Swoole을 사용하여 단일 PHP 프로세스 내에서 여러 시간/IO 관련 테스트를 동시에 실행할 수 있습니다. Counit은 PHPUnit 과 호환되며 이는 다음을 의미합니다.
counit 의 일반적인 테스트 케이스는 다음과 같습니다.
use Deminy Counit TestCase ; // Here is the only change made for counit, comparing to test cases for PHPUnit.
class SleepTest extends TestCase
{
public function testSleep (): void
{
$ startTime = time ();
sleep ( 3 );
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
}
}
PHPUnit 과 비교하여 counit은 테스트 사례를 더 빠르게 만들 수 있습니다. 다음은 실제 프로젝트에서 PHPUnit 과 counit을 사용하여 동일한 테스트 스위트를 실행할 때의 비교입니다. 테스트 스위트에서 많은 테스트는 DeminyCounitCounit::sleep() 메소드를 호출하여 어떤 일이 일어나기를 기다립니다(예: 데이터가 만료되기를 기다림).
테스트 수 | 주장 수 | 완료 시간 | |
---|---|---|---|
counit(Swoole 제외) 또는 PHPUnit | 44 | 1148 | 9분 18초 |
카운티(Swoole 활성화됨) | 19초 |
Composer를 사용하여 패키지를 설치할 수 있습니다.
composer require deminy/counit --dev
또는 Composer.json 파일에 패키지 deminy/counit이 포함되어 있는지 확인하세요.
{
"require-dev" : {
"deminy/counit" : " ~0.2.0 "
}
}
폴더 ./tests/unit/global 및 ./tests/unit/case-by-case에는 다음과 같은 시간 관련 테스트가 포함된 몇 가지 샘플 테스트가 포함되어 있습니다.
샘플 테스트를 실행하려면 먼저 Docker 컨테이너를 시작하고 Composer 패키지를 설치하세요.
docker-compose up -d
docker compose exec -ti swoole composer install -n
PHP 컨테이너, Swoole 컨테이너, Redis 컨테이너, MySQL 컨테이너, 웹 서버 등 5개의 컨테이너가 시작되었습니다. PHP 컨테이너에는 Swoole 확장이 설치되어 있지 않지만 Swoole 컨테이너에는 Swoole 확장이 설치되어 활성화되어 있습니다.
이전에 말했듯이 테스트 케이스는 PHPUnit 과 동일한 방식으로 작성될 수 있습니다. 그러나 counit 을 사용하여 시간/IO 관련 테스트를 더 빠르게 실행하려면 해당 테스트 사례를 작성할 때 몇 가지 조정이 필요합니다. 이러한 조정은 두 가지 다른 스타일로 이루어질 수 있습니다.
이 스타일에서는 각 테스트 사례가 별도의 코루틴에서 자동으로 실행됩니다.
이 스타일로 작성된 테스트 케이스의 경우 기존 테스트 케이스에서 변경해야 할 유일한 변경 사항은 PHPUnitFrameworkTestCase 대신 DeminyCounitTestCase 클래스를 기본 클래스로 사용하는 것입니다.
전역 스타일의 일반적인 테스트 사례는 다음과 같습니다.
use Deminy Counit TestCase ; // Here is the only change made for counit, comparing to test cases for PHPUnit.
class SleepTest extends TestCase
{
public function testSleep (): void
{
$ startTime = time ();
sleep ( 3 );
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
}
}
사용자 정의된 메소드 setUpBeforeClass() 및 TearDownAfterClass() 가 테스트 케이스에 정의된 경우 이러한 사용자 정의된 메소드에 따라 상위 메소드를 호출해야 합니다.
이 스타일은 테스트 사례에 즉각적인 어설션이 없고 sleep() 함수 호출 또는 코루틴 친화적인 IO 작업 이전에 어설션이 없다고 가정합니다. 다음과 같은 테스트 사례는 여전히 작동하지만 테스트 시 일부 경고 메시지가 트리거됩니다.
class GlobalTest extends Deminy Counit TestCase
{
public function testAssertionSuppression (): void
{
self :: assertTrue ( true , ' Trigger an immediate assertion. ' );
// ......
}
}
경고 메시지를 제거하기 위해 "사례별" 스타일(다음 섹션에서 설명)을 사용하여 이 테스트 클래스를 다시 작성할 수 있습니다.
이 스타일로 작성된 더 많은 테스트를 찾으려면 ./tests/unit/global 폴더(테스트 모음 "global")에서 테스트를 확인하세요.
이 스타일에서는 테스트 사례를 직접 변경하여 비동기식으로 작동하도록 합니다.
이 스타일로 작성된 테스트 케이스의 경우 PHP 실행을 기다리거나 IO 작업을 수행해야 하는 테스트 케이스에 맞게 DeminyCounitCounit 클래스를 사용해야 합니다. 일반적으로 다음 메서드 호출이 사용됩니다.
사례별 스타일의 일반적인 테스트 사례는 다음과 같습니다.
use Deminy Counit Counit ;
use PHPUnit Framework TestCase ;
class SleepTest extends TestCase
{
public function testSleep (): void
{
Counit:: create ( function () { // To create a new coroutine manually to run the test case.
$ startTime = time ();
Counit:: sleep ( 3 ); // Call this method instead of PHP function sleep().
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
});
}
}
"이 테스트는 어설션을 수행하지 않았습니다"라는 경고 메시지를 표시하지 않거나 어설션 수를 일치시켜야 하는 경우 새 코루틴을 생성할 때 두 번째 매개변수를 포함할 수 있습니다.
use Deminy Counit Counit ;
use PHPUnit Framework TestCase ;
class SleepTest extends TestCase
{
public function testSleep (): void
{
Counit:: create ( // To create a new coroutine manually to run the test case.
function () {
$ startTime = time ();
Counit:: sleep ( 3 ); // Call this method instead of PHP function sleep().
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
},
1 // Optional. To suppress warning message "This test did not perform any assertions", and to make the counters match.
);
}
}
이 스타일로 작성된 더 많은 테스트를 찾으려면 ./tests/unit/case-by-case 폴더에서 테스트를 확인하세요(테스트 모음 "case-by-case").
여기에서는 Swoole 유무에 관계없이 다양한 환경에서 테스트를 실행합니다.
#1
PHPUnit을 사용하여 테스트 스위트 실행:
# To run test suite "global":
docker compose exec -ti php ./vendor/bin/phpunit --testsuite global
# or,
docker compose exec -ti swoole ./vendor/bin/phpunit --testsuite global
# To run test suite "case-by-case":
docker compose exec -ti php ./vendor/bin/phpunit --testsuite case-by-case
# or,
docker compose exec -ti swoole ./vendor/bin/phpunit --testsuite case-by-case
#2
counit을 사용하여 테스트 스위트를 실행합니다(Swoole 없이):
# To run test suite "global":
docker compose exec -ti php ./counit --testsuite global
# To run test suite "case-by-case":
docker compose exec -ti php ./counit --testsuite case-by-case
#3
counit을 사용하여 테스트 스위트를 실행합니다(확장 Swoole 사용).
# To run test suite "global":
docker compose exec -ti swoole ./counit --testsuite global
# To run test suite "case-by-case":
docker compose exec -ti swoole ./counit --testsuite case-by-case
처음 두 명령 세트는 완료하는 데 거의 같은 시간이 걸립니다. 마지막 명령 세트는 counit을 사용하고 Swoole 컨테이너(Swoole 확장이 활성화된 곳)에서 실행됩니다. 따라서 다른 것보다 빠릅니다.
스타일 | 테스트 수 | 주장 수 | 완료 시간 | |
---|---|---|---|---|
counit(Swoole 제외) 또는 PHPUnit | 글로벌 | 16 | 24 | 48초 |
경우에 따라 | 48초 | |||
카운티(Swoole 활성화됨) | 글로벌 | 7초 | ||
경우에 따라 | 7초 |
이 패키지를 사용하면 여러 테스트를 동시에 실행할 수 있으므로 서로 다른 테스트에서 동일한 리소스를 사용해서는 안 됩니다. 그렇지 않으면 경주 조건이 발생할 수 있습니다. 예를 들어 여러 테스트가 동일한 Redis 키를 사용하는 경우 일부 테스트가 때때로 실패할 수 있습니다. 이 경우 테스트 사례마다 다른 Redis 키를 사용해야 합니다. DeminyCounitHelper::getNewKey() 및 DeminyCounitHelper::getNewKeys() 메소드를 사용하여 임의의 고유한 테스트 키를 생성할 수 있습니다.
이 패키지는 sleep() 함수 호출을 사용하는 테스트에 가장 적합합니다. 또한 일부 IO 관련 테스트를 더 빠르게 실행하는 데 도움이 될 수 있지만 제한 사항이 적용됩니다. 이 패키지의 제한 사항 목록은 다음과 같습니다.
샘플 테스트를 실행하기 위해 사전 구축된 이미지 데미니/군집이 있습니다. 이미지를 빌드하는 명령은 다음과 같습니다.
docker build -t deminy/counit:php-only -f ./dockerfiles/php/Dockerfile .
docker build -t deminy/counit:swoole-enabled -f ./dockerfiles/swoole/Dockerfile .
이 패키지를 사용하면 Swoole을 사용하여 다중 처리 없이 여러 시간/IO 관련 테스트를 실행할 수 있습니다. 이는 모든 테스트가 단일 PHP 프로세스 내에서 실행될 수 있음을 의미합니다. 이것이 정확히 어떻게 작동하는지 이해하려면 무료 온라인 강연인 PHP의 CSP 프로그래밍(여기 슬라이드도 있음)을 확인하는 것이 좋습니다.
PHP 생태계에는 단위 테스트를 병렬로 실행하는 다른 옵션이 있으며 대부분은 다중 처리를 사용합니다.
MIT 라이센스.