1. 일반적인 테스트 예시
우리는 종종 이런 상황에 직면합니다. 테스트되지 않은 일부 레거시 코드가 다시 작성되고 테스트되고, 심지어 이러한 코드도 여전히 객체 지향 모드로 작성됩니다. 이와 같은 코드를 테스트하려면 코드를 여러 덩어리로 나누어 테스트하기가 더 쉽도록 조언합니다.
그러나 이러한 레거시 코드는 리팩터링이 쉽지 않습니다. 예를 들어 테스트하기 전에 코드를 다시 작성할 수는 없습니다. 이는 원본 프로그램에 영향을 주지 않기 위한 것이며, 물론 단위 테스트를 수행하는 것도 쉽지 않습니다.
PHP 프로그램에서 코드의 일부는 일반적으로 여러 index.php 및 script.php 파일에 작성되며 이러한 .php 파일은 여러 다른 폴더에 저장됩니다. 진입점을 찾을 수 없으면 웹 서버에서 직접 액세스할 수 없습니다.
테스트 카피
PHP 스크립트를 테스트하려면 HTTP 요청을 시뮬레이션하고 반환된 응답이 예상 값과 같은지 확인해야 합니다. 여기서 주목해야 할 점은 요청을 시뮬레이션하고 응답과 요청을 정의하는 것입니다. 내용뿐만 아니라 헤더도 다릅니다.
또한 데이터를 조작하는 트랜잭션 스크립트를 테스트하려는 경우 해당 스크립트가 실제 데이터베이스나 나머지 애플리케이션에 연결되지 않도록 해야 합니다.
실제로는 테스트를 위해 원래 PHP 스크립트를 직접 다시 작성하는 사람이 거의 없습니다. 코드를 복구할 수 없게 만드는 것이 두렵기 때문입니다. PHP 코드에 대해 몇 가지 간단한 작업을 수행할 수 있도록 PHP 스크립트 복사본을 사용하는 것이 좋습니다.
코드 수정을 최소화하는 방법: include 및 require 문(사용하지 않는 경우)을 삭제하고 내부 함수가 호출되는 방식을 수정합니다. 예: header()를 $object->header()로 작성 .
마지막으로 이 거래 스크립트를 테스트해 보겠습니다. 테스트 후에는 중복 스크립트에서 이를 추출하여 새 스크립트 파일에 배치할 수 있습니다.
구체적인 단계
1. HTTP 요청을 시뮬레이션하고 $_GET 및 $_POST 변수를 재정의하고 $_SERVER의 헤더도 수정합니다.
2. 요청 응답을 가져옵니다. 응답 본문은 ob_start() 및 ob_get_clean()을 통해 캡처할 수 있습니다. echo() 또는
참고: 출력 버퍼링은 PHP에서 여러 수준의 중첩을 지원하므로 스크립트가 ob_* 호출 자체를 사용하는 경우에도 대부분의 경우가 캡처됩니다.
3. 테스트 스크립트에는 트랜잭션 스크립트의 내부 메소드가 포함되어 있어야 이 스크립트 범위 내의 모든 메소드를 호출할 수 있습니다. 예:
1. 스크립트에 필요한 변수는 로컬 변수로 정의되고 $connection과 같이 데이터베이스 연결로 캡슐화될 수 있습니다.
2. PHP의 원래 내장 함수가 아닙니다. 예를 들어 header()는 $this->header()로 작성됩니다.
특정코드
이것은 우리가 테스트하려는 거래 스크립트 개체입니다. 스크립트와 관련하여 이를 캡슐화해야 합니다.
<?php class ForumPosting { private $headers = array(); public function handleRequest($postRequest) { $_POST = $postRequest; $connection = $this->getAConnection(); ob_start(); include 'forum/post_new_copy.php'; $content = ob_get_clean(); return array( 'content' => $content, 'headers' => $this->headers ); } private function header($headerLine) { $this->headers[] = $headerLine; } ... }
테스트 코드는 다음과 같습니다.
public function testANewPostIsCreated() { $action = new ForumPosting(); $response = $action->handleRequest(array( 'id_thread' => 42, 'text' => 'Hello, world', ... )); $this->assertEquals('...', $response['content']); $this->assertContains('Content-type: text/html', $response['headers']); }
테스트 사본은 일시적일 뿐입니다! 이를 통해 변경되지 않는 테스트를 작성할 수 있습니다. 마지막으로 테스트를 통과한 PHP 스크립트를 리팩터링하여 중복 코드를 제거하겠습니다.
테스트가 완료되면 handlerRequest()의 내용이 실제 논리 코드로 대체될 수 있습니다. 이러한 테스트 스크립트를 많이 작성하려면 테스트 요구 사항을 충족하는 일반 테스트 개체를 작성할 수 있습니다.
2. PHP 개발자를 위한 단위 테스트 툴킷
PHP 분야에는 PHPUNIT, PHPUNIT2, SimpleTest라는 세 가지 주요 단위 테스트 도구가 있습니다. 그 중 PHPUNIT는 기능이 매우 단순하지만 완벽하지는 않습니다. PHPUNIT2는 구조와 기능이 Junit과 일치하는 PHP5용으로 특별히 작성된 단위 테스트 도구이며 SimpleTest는 매우 실용적인 테스트 도구입니다. 웹 프로그램 인터페이스는 Easy에서 가장 권장하는 테스트 도구입니다. 이 기사에서는 소개를 위해 SimpleTest를 선택했습니다.
관련 지식: PHPUNIT2는 특히 아키텍처 측면에서 매우 좋은 도구입니다. 나중에 관련 기사를 통해 여러분과 공유할 기회가 있기를 바랍니다.
간단한 테스트: 정말 간단합니다
SimpleTest 설치는 매우 간단합니다. sf.net에서 소스 코드 패키지를 다운로드한 다음 웹 디렉토리에 압축을 풀면 여기서는 자세히 설명하지 않겠습니다.
먼저 예를 살펴보겠습니다. 웹사이트에 액세스할 수 있는지 확인하는 테스트를 작성하세요.
먼저 사용할 파일을 소개합니다.
코드 목록:
require_once("../simpletest/unit_tester.php"); require_once("../simpletest/web_tester.php"); require_once("../simpletest/reporter.php");
그런 다음 테스트 클래스를 만듭니다.
코드 목록:
class TestOfSite extends WebTestCase { function TestOfSite() { $this->WebTestCase("测试"); } function testSite() { $this->get("http://howgo.net/prettyface/display.php"); $this->assertTitle(".: facebook :."); } }
首先我们扩展了webTestCase类,这样我们就可以自动获得测试web的能力,然后在构造函数中我们直接使用基类的,只是把标题传给它。接着我们就该写测试方法了,测试方法都是以‘test"开头的,用以识别在我们运行测试的时候,类中哪些方法要进行调用。
而$this->get将取得网页的内容,我们指定它的标题为 ".: facebook :.", 接着我们要做的就是实例化这个类的对象,并运行它。
代码列表:
$test = &new TestOfSite(); $test->run(new HtmlReporter());
下边是运行结果:
如果测试出错则会出现下边的界面:
到这里一个简单的测试就算完成了。
实战演习 – 一个Login测试
下面我们进入实战,在这个基础上完成一个login的测试。这次我们先贴出完整的代码:
代码列表:
require_once("../simpletest/unit_tester.php"); require_once("../simpletest/web_tester.php"); require_once("../simpletest/reporter.php"); class TestOfLogin extends WebTestCase { function TestOfLogin() { $this->WebTestCase("Login测试"); } function testLoginOk() { // 取得页面 $this->get("http://howgo.net/prettyface/login.php"); // 添加测试表项 $this->setField("name","Easy"); $this->setField("pass","******"); // 提交 $this->clickSubmit("提交"); // 察看提交后返回页面是否正确 $this->assertWantedPattern("/成功登录/"); // 点击页面链接 $this->clickLink("点击这里进入管理页面"); // 察看指定页面标题和关键内容 $this->assertTitle("ADMINCP"); $this->assertWantedPattern("/请选择要进行的任务/"); // 退出登陆 $this->clickLink("退出管理"); $this->clickLink } }