PHPUnitManual:4.1

From 흡혈양파의 번역工房
Jump to navigation Jump to search
4.1 테스트의 의존성

테스트의 의존성

Unit Tests are primarily written as a good practice to help developers identify and fix bugs, to refactor code and to serve as documentation for a unit of software under test. To achieve these benefits, unit tests ideally should cover all the possible paths in a program. One unit test usually covers one specific path in one function or method. However a test method is not necessary an encapsulated, independent entity. Often there are implicit dependencies between test methods, hidden in the implementation scenario of a test.

단위 테스트 (unit test) 를 작성하는 근본적인 목적은, 버그의 발견과 수정, 코드 리팩토링의 용이성, 테스트 대상에 관한 문서 역할이다. 이 목적을 달성하기 위해서는, 단위 테스트가 프로그램 안의 모든 경우의 흐름 (route) 를 커버하는 것이 이상적이다. 하나의 단위 테스트가 커버하는 범위는, 일반적으로 하나의 함수나 메소드 안의 특정 한 흐름이다. 하지만 테스트 메소드는 캡슐화를 통해 독립시켜야만 할 필요는 없다. 복수의 테스트 메소드 간에 암묵적인 의존성이 있어서 드러나지 않은 실동작 시나리오가 테스트 안에 존재하는 것은 흔하다. - Adrian Kuhn et. al.


PHPUnit 에서는 테스트 메소드 간의 의존성을 명시적으로 선언할 수 있습니다. 여기서 말하는 의존성이란, 테스트 메소드가 실행되는 순서를 정의하는 것은 아닙니다. 생산자 (producer) 가 테스트 fixture 를 만들어 fixture 의 인스턴스를 반환 (return) 하고, 이에 의존하는 소비자 (consumer) 가 인스턴스를 받아 이용하는 것입니다.

  • 생산자란, 테스트 대상의 유닛을 생성하여 반환하는 테스트 메소드이다
  • 소비자란, 생산자가 반환값에 의존하는 테스트 메소드입니다.


예제 4.2 @depends 선언을 이용한 의존성의 표현

<?php
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);
	}
}
?>


위 예에서는, 첫번째 테스트인 testEmpty() 에서 새 배열을 만들고, 배열이 비어 있음을 확인합니다. 이 테스트는 fixture 를 반환합니다. 두번째 테스트인 testPush() 는 testEmpty() 에 의존하고 있기에 의존하는 테스트의 결과를 인수로 받습니다. 마지막 testPop() 는 testPush() 에 의존하고 있습니다.


문제 범위를 빠르게 찾기 위해서는, 실패한 테스트를 쉽게 발견하게 하여야 합니다. 이 때문에 PHPUnit 에서는, 하나의 테스트가 실패한 경우, 그 테스트에 의존하는 다른 테스트의 실행을 스킵합니다. 예제 4.3 "테스트의 의존성의 활용" 은 테스트 간의 의존성을 활용하여 문제점을 쉽게 발견하게 되는 예입니다.


예제 4.3 테스트의 의존성의 활용

<?php
class DependencyFailureTest extends PHPUnit_Framework_TestCase
{
	public function testOne()
	{
		$this->assertTrue(FALSE);
	}
	/**
	 * @depends testOne
	 */
	public function testTwo()
	{
	}
}
?>
PHPUnit 3.7.0 by Sebastian Bergmann.
FS
Time: 0 seconds, Memory: 5.00Mb
There was 1 failure:
1) DependencyFailureTest::testOne
Failed asserting that false is true.
/home/sb/DependencyFailureTest.php:6
There was 1 skipped test:
1) DependencyFailureTest::testTwo
This test depends on "DependencyFailureTest::testOne" to pass.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.phpunit --verbose DependencyFailureTest
PHPUnit 3.7.0 by Sebastian Bergmann.
FS
Time: 0 seconds, Memory: 5.00Mb
There was 1 failure:
1) DependencyFailureTest::testOne
Failed asserting that false is true.
/home/sb/DependencyFailureTest.php:6
There was 1 skipped test:
1) DependencyFailureTest::testTwo
This test depends on "DependencyFailureTest::testOne" to pass.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.


하나의 테스트에 복수의 @depends 주석을 달 수도 있습니다. PHPUnit 은 테스트가 실행되는 순서를 변경하지 않기 때문에, 테스트가 실행될 때 확실하게 의존성을 만족시키도록 할 필요가 있습니다.