수색…
통사론
- 단언의 완전한 목록 . 예 :
-
assertTrue(bool $condition[, string $messageIfFalse = '']);
-
assertEquals(mixed $expected, mixed $actual[, string $messageIfNotEqual = '']);
비고
Unit
테스트는 소스 코드를 테스트하여 예상되는 입력을 처리하는지 여부를 확인하는 데 사용됩니다. Unit
테스트는 대부분의 프레임 워크에서 지원됩니다. PHPUnit 테스트 에는 여러 가지가 있으며 구문이 다를 수 있습니다. 이 예제에서는 PHPUnit
사용하고 있습니다.
클래스 규칙 테스트
규칙 () 메소드가있는 간단한 LoginForm
클래스 (프레임 워크 템플릿으로 로그인 페이지에서 사용됨)가 있다고 가정 해 보겠습니다.
class LoginForm {
public $email;
public $rememberMe;
public $password;
/* rules() method returns an array with what each field has as a requirement.
* Login form uses email and password to authenticate user.
*/
public function rules() {
return [
// Email and Password are both required
[['email', 'password'], 'required'],
// Email must be in email format
['email', 'email'],
// rememberMe must be a boolean value
['rememberMe', 'boolean'],
// Password must match this pattern (must contain only letters and numbers)
['password', 'match', 'pattern' => '/^[a-z0-9]+$/i'],
];
}
/** the validate function checks for correctness of the passed rules */
public function validate($rule) {
$success = true;
list($var, $type) = $rule;
foreach ((array) $var as $var) {
switch ($type) {
case "required":
$success = $success && $this->$var != "";
break;
case "email":
$success = $success && filter_var($this->$var, FILTER_VALIDATE_EMAIL);
break;
case "boolean":
$success = $success && filter_var($this->$var, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null;
break;
case "match":
$success = $success && preg_match($rule["pattern"], $this->$var);
break;
default:
throw new \InvalidArgumentException("Invalid filter type passed")
}
}
return $success;
}
}
이 클래스에 대한 테스트를 수행하기 위해 Unit 테스트 (소스 코드를 확인하여 기대에 부합하는지 확인)를 사용합니다.
class LoginFormTest extends TestCase {
protected $loginForm;
// Executing code on the start of the test
public function setUp() {
$this->loginForm = new LoginForm;
}
// To validate our rules, we should use the validate() method
/**
* This method belongs to Unit test class LoginFormTest and
* it's testing rules that are described above.
*/
public function testRuleValidation() {
$rules = $this->loginForm->rules();
// Initialize to valid and test this
$this->loginForm->email = "[email protected]";
$this->loginForm->password = "password";
$this->loginForm->rememberMe = true;
$this->assertTrue($this->loginForm->validate($rules), "Should be valid as nothing is invalid");
// Test email validation
// Since we made email to be in email format, it cannot be empty
$this->loginForm->email = '';
$this->assertFalse($this->loginForm->validate($rules), "Email should not be valid (empty)");
// It does not contain "@" in string so it's invalid
$this->loginForm->email = 'invalid.email.com';
$this->assertFalse($this->loginForm->validate($rules), "Email should not be valid (invalid format)");
// Revert email to valid for next test
$this->loginForm->email = '[email protected]';
// Test password validation
// Password cannot be empty (since it's required)
$this->loginForm->password = '';
$this->assertFalse($this->loginForm->validate($rules), "Password should not be valid (empty)");
// Revert password to valid for next test
$this->loginForm->password = 'ThisIsMyPassword';
// Test rememberMe validation
$this->loginForm->rememberMe = 999;
$this->assertFalse($this->loginForm->validate($rules), "RememberMe should not be valid (integer type)");
// Revert remeberMe to valid for next test
$this->loginForm->rememberMe = true;
}
}
Unit
테스트가 여기에 도움이 될 수있는 방법은 무엇입니까 (일반적인 예제 제외)? 예를 들어, 예상치 못한 결과가 나올 때 아주 잘 맞습니다. 예를 들어,이 규칙을 앞에서 취해 보겠습니다.
['password', 'match', 'pattern' => '/^[a-z0-9]+$/i'],
대신, 우리가 한 가지 중요한 것을 놓치고 이것을 썼다면 :
['password', 'match', 'pattern' => '/^[a-z0-9]$/i'],
수십 개의 다른 규칙 (전자 메일과 암호 만 사용하는 것이 아니라고 가정)을 사용하면 실수를 감지하기가 어렵습니다. 이 단위 테스트 :
// Initialize to valid and test this
$this->loginForm->email = "[email protected]";
$this->loginForm->password = "password";
$this->loginForm->rememberMe = true;
$this->assertTrue($this->loginForm->validate($rules), "Should be valid as nothing is invalid");
첫 번째 예는 통과하지만 두 번째 예는 통과하지 않습니다. 왜? 두 번째 예에서는 오타 (누락 된 +
기호)가있는 패턴을 작성 했으므로 하나의 문자 / 숫자 만 허용합니다.
단위 테스트는 phpunit [path_to_file]
명령으로 콘솔에서 실행할 수 있습니다. 모든 것이 정상이면 모든 테스트가 OK
상태인지 확인해야합니다. 그렇지 않으면 Error
(구문 오류) 또는 Fail
(해당 메서드에서 적어도 한 줄은 통과하지 못했음)가 표시됩니다.
--coverage
와 같은 추가 매개 변수를 사용하여 백엔드 코드의 몇 줄이 테스트되었고 통과 / 실패했는지 시각적으로 볼 수 있습니다. 이것은 PHPUnit 을 설치 한 모든 프레임 워크에 적용됩니다.
PHPUnit
테스트가 콘솔에서 어떻게 보이는지 예제 (이 예제에 따르지 않는 일반적인 모양) :
PHPUnit 데이터 제공 업체
테스트 방법에서는 종종 테스트 할 데이터가 필요합니다. 일부 메소드를 완전히 테스트하려면 가능한 모든 테스트 조건에 대해 서로 다른 데이터 세트를 제공해야합니다. 물론 다음과 같이 루프를 사용하여 수동으로 할 수 있습니다.
...
public function testSomething()
{
$data = [...];
foreach($data as $dataSet) {
$this->assertSomething($dataSet);
}
}
...
누군가가 편리하다는 것을 알 수 있습니다. 그러나이 접근법에는 몇 가지 단점이 있습니다. 먼저, 테스트 함수가 여러 매개 변수를 허용하는 경우 데이터를 추출하기 위해 추가 작업을 수행해야합니다. 둘째, 실패시 추가 메시지 및 디버깅없이 실패한 데이터 세트를 구별하기가 어려울 수 있습니다. 셋째, PHPUnit은 데이터 공급자를 사용하여 테스트 데이터 세트를 자동으로 처리합니다.
데이터 공급자는 특정 테스트 케이스에 대한 데이터를 반환해야하는 함수입니다.
데이터 공급자 메서드는 public이어야하며 Iterator 인터페이스를 구현하는 배열 또는 개체 의 배열을 반환하고 각 반복 단계마다 배열 을 생성해야합니다 . 컬렉션의 일부인 각 배열에 대해 배열의 내용을 인수로 사용하여 테스트 메서드가 호출됩니다.
테스트에 데이터 공급자를 사용하려면 지정된 데이터 공급자 함수 이름과 함께 @dataProvider
주석을 사용합니다.
/**
* @dataProvider dataProviderForTest
*/
public function testEquals($a, $b)
{
$this->assertEquals($a, $b);
}
public function dataProviderForTest()
{
return [
[1,1],
[2,2],
[3,2] //this will fail
];
}
배열의 배열
dataProviderForTest()
는 배열의 배열을 반환합니다. 중첩 된 각 배열에는 두 개의 요소가 있으며testEquals()
필요한 매개 변수를testEquals()
채 웁니다. 이렇게 오류가 발생합니다. 충분한 요소가없는 경우Missing argument 2 for Test::testEquals()
됩니다. PHPUnit은 자동으로 데이터를 순환하고 테스트를 실행합니다 :
public function dataProviderForTest()
{
return [
[1,1], // [0] testEquals($a = 1, $b = 1)
[2,2], // [1] testEquals($a = 2, $b = 2)
[3,2] // [2] There was 1 failure: 1) Test::testEquals with data set #2 (3, 4)
];
}
편의를 위해 각 데이터 세트의 이름 을 지정할 수 있습니다. 실패한 데이터를 쉽게 감지 할 수 있습니다.
public function dataProviderForTest()
{
return [
'Test 1' => [1,1], // [0] testEquals($a = 1, $b = 1)
'Test 2' => [2,2], // [1] testEquals($a = 2, $b = 2)
'Test 3' => [3,2] // [2] There was 1 failure:
// 1) Test::testEquals with data set "Test 3" (3, 4)
];
}
반복기
class MyIterator implements Iterator {
protected $array = [];
public function __construct($array) {
$this->array = $array;
}
function rewind() {
return reset($this->array);
}
function current() {
return current($this->array);
}
function key() {
return key($this->array);
}
function next() {
return next($this->array);
}
function valid() {
return key($this->array) !== null;
}
}
...
class Test extends TestCase
{
/**
* @dataProvider dataProviderForTest
*/
public function testEquals($a)
{
$toCompare = 0;
$this->assertEquals($a, $toCompare);
}
public function dataProviderForTest()
{
return new MyIterator([
'Test 1' => [0],
'Test 2' => [false],
'Test 3' => [null]
]);
}
}
보시다시피 단순한 반복자도 작동합니다.
단일 매개 변수의 경우에도 데이터 공급자는 배열
[$parameter]
반환해야합니다[$parameter]
왜냐하면 우리는 current()
메소드 (모든 반복에서 실제로 데이터를 리턴)를 this로 변경하면 :
function current() {
return current($this->array)[0];
}
또는 실제 데이터를 변경하십시오.
return new MyIterator([
'Test 1' => 0,
'Test 2' => false,
'Test 3' => null
]);
오류가 발생합니다.
There was 1 warning:
1) Warning
The data provider specified for Test::testEquals is invalid.
물론, 간단한 배열을 통해
Iterator
객체를 사용하는 것은 유용하지 않습니다. 그것은 당신의 사건에 대한 몇 가지 구체적인 논리를 구현해야합니다.
발전기
그것은 명시 적으로 언급되지 않고 매뉴얼에 표시되어 있지만 데이터 제공자로 발전기 를 사용할 수도 있습니다. Generator
클래스는 실제로 Iterator
인터페이스를 구현합니다.
다음은 generator
와 결합 된 DirectoryIterator
의 사용 예입니다.
/**
* @param string $file
*
* @dataProvider fileDataProvider
*/
public function testSomethingWithFiles($fileName)
{
//$fileName is available here
//do test here
}
public function fileDataProvider()
{
$directory = new DirectoryIterator('path-to-the-directory');
foreach ($directory as $file) {
if ($file->isFile() && $file->isReadable()) {
yield [$file->getPathname()]; // invoke generator here.
}
}
}
주 공급자
yield
배열이야. 대신 잘못된 데이터 공급자 경고가 표시됩니다.
예외 테스트
예외를 throw하는 메서드를 테스트하려고한다고 가정 해 봅시다.
class Car
{
/**
* @throws \Exception
*/
public function drive()
{
throw new \Exception('Useful message', 1);
}
}
메서드 호출을 try / catch 블록으로 묶고 실행 객체의 속성에 대한 어설 션을 작성하면이 작업을 수행 할 수 있지만보다 편리하게 예외 어설 션 메서드를 사용할 수 있습니다. PHPUnit 5.2에서 expectX () 메소드를 사용하여 예외 유형, 메시지 및 코드를 선언 할 수 있습니다.
class DriveTest extends PHPUnit_Framework_TestCase
{
public function testDrive()
{
// prepare
$car = new \Car();
$expectedClass = \Exception::class;
$expectedMessage = 'Useful message';
$expectedCode = 1;
// test
$this->expectException($expectedClass);
$this->expectMessage($expectedMessage);
$this->expectCode($expectedCode);
// invoke
$car->drive();
}
}
이전 버전의 PHPUnit을 사용하는 경우 expectX () 메소드 대신 setExpectedException 메소드를 사용할 수 있지만 더 이상 사용되지 않으며 버전 6에서 제거됩니다.
class DriveTest extends PHPUnit_Framework_TestCase
{
public function testDrive()
{
// prepare
$car = new \Car();
$expectedClass = \Exception::class;
$expectedMessage = 'Useful message';
$expectedCode = 1;
// test
$this->setExpectedException($expectedClass, $expectedMessage, $expectedCode);
// invoke
$car->drive();
}
}