当前位置:  开发笔记 > 编程语言 > 正文

如何在PHP中编写单元测试?

如何解决《如何在PHP中编写单元测试?》经验,为你挑选了6个好方法。

我到处都读到它们有多棒,但由于某些原因,我似乎无法弄清楚我到底应该测试一些东西.有人可能会发布一段示例代码以及他们将如何测试它?如果不是太麻烦:)



1> Till..:

有一个第三个"框架",它更容易学习 - 甚至比简单测试更容易,它被称为phpt.

可以在这里找到一本入门书:http: //qa.php.net/write-test.php

编辑:刚看到您的示例代码请求.

假设您在名为lib.php的文件中具有以下函数:


非常简单直接,返回您传入的参数.那么让我们看看这个函数的测试,我们将调用测试文件foo.phpt:

--TEST--
foo() function - A basic test to see if it works. :)
--FILE--

--EXPECT--
string(11) "Hello World"

简而言之,我们提供$bar带有值的参数,"Hello World"以及var_dump()函数调用的响应foo().

要运行此测试,请使用: pear run-test path/to/foo.phpt

这需要在您的系统上安装PEAR,这在大多数情况下非常常见.如果您需要安装它,我建议安装最新版本.如果您需要帮助进行设置,请随时询问(但提供操作系统等).



2> okoman..:

您可以使用两个框架进行单元测试.Simpletest和PHPUnit,我更喜欢.阅读有关如何在PHPUnit主页上编写和运行测试的教程.这很简单,也很好描述.



3> Preston..:

您可以通过更改编码样式来使单元测试更有效.

我建议浏览Google测试博客,特别是关于编写可测试代码的帖子.


我想你提到了一篇很棒的文章.以"单元测试不是非常有效"开始你的回答几乎让我失败了,但是,作为一个测试专家...可能,以积极的方式改写将鼓励人们阅读文章.
@xtofl编辑它以稍微提高'积极性':)

4> Kris..:

我自己动手,因为我没有时间学习别人的做事方式,这需要大约20分钟的时间来写,10个以适应它在这里发布.

单元测试对我来说非常有用.

这有点长,但它解释了自己,底部有一个例子.

/**
 * Provides Assertions
 **/
class Assert
{
    public static function AreEqual( $a, $b )
    {
        if ( $a != $b )
        {
            throw new Exception( 'Subjects are not equal.' );
        }
    }
}

/**
 * Provides a loggable entity with information on a test and how it executed
 **/
class TestResult
{
    protected $_testableInstance = null;

    protected $_isSuccess = false;
    public function getSuccess()
    {
        return $this->_isSuccess;
    }

    protected $_output = '';
    public function getOutput()
    {
        return $_output;
    }
    public function setOutput( $value )
    {
        $_output = $value;
    }

    protected $_test = null;
    public function getTest()
    {
        return $this->_test;
    }

    public function getName()
    {
        return $this->_test->getName();
    }
    public function getComment()
    {
        return $this->ParseComment( $this->_test->getDocComment() );
    }

    private function ParseComment( $comment )
    {
        $lines = explode( "\n", $comment );
        for( $i = 0; $i < count( $lines ); $i ++ )
        {
            $lines[$i] = trim( $lines[ $i ] );
        }
        return implode( "\n", $lines );
    }

    protected $_exception = null;
    public function getException()
    {
        return $this->_exception;
    }

    static public function CreateFailure( Testable $object, ReflectionMethod $test, Exception $exception )
    {
        $result = new self();
        $result->_isSuccess = false;
        $result->testableInstance = $object;
        $result->_test = $test;
        $result->_exception = $exception;

        return $result;
    }
    static public function CreateSuccess( Testable $object, ReflectionMethod $test )
    {
        $result = new self();
        $result->_isSuccess = true;
        $result->testableInstance = $object;
        $result->_test = $test;

        return $result;
    }
}

/**
 * Provides a base class to derive tests from
 **/
abstract class Testable
{
    protected $test_log = array();

    /**
     * Logs the result of a test. keeps track of results for later inspection, Overridable to log elsewhere.
     **/
    protected function Log( TestResult $result )
    {
        $this->test_log[] = $result;

        printf( "Test: %s was a %s %s\n"
            ,$result->getName()
            ,$result->getSuccess() ? 'success' : 'failure'
            ,$result->getSuccess() ? '' : sprintf( "\n%s (lines:%d-%d; file:%s)"
                ,$result->getComment()
                ,$result->getTest()->getStartLine()
                ,$result->getTest()->getEndLine()
                ,$result->getTest()->getFileName()
                )
            );

    }
    final public function RunTests()
    {
        $class = new ReflectionClass( $this );
        foreach( $class->GetMethods() as $method )
        {
            $methodname = $method->getName();
            if ( strlen( $methodname ) > 4 && substr( $methodname, 0, 4 ) == 'Test' )
            {
                ob_start();
                try
                {
                    $this->$methodname();
                    $result = TestResult::CreateSuccess( $this, $method );
                }
                catch( Exception $ex )
                {
                    $result = TestResult::CreateFailure( $this, $method, $ex );
                }
                $output = ob_get_clean();
                $result->setOutput( $output );
                $this->Log( $result );
            }
        }
    }
}

/**
 * a simple Test suite with two tests
 **/
class MyTest extends Testable
{
    /**
     * This test is designed to fail
     **/
    public function TestOne()
    {
        Assert::AreEqual( 1, 2 );
    }

    /**
     * This test is designed to succeed
     **/
    public function TestTwo()
    {
        Assert::AreEqual( 1, 1 );
    }
}

// this is how to use it.
$test = new MyTest();
$test->RunTests();

这输出:

Test: TestOne was a failure 
/**
* This test is designed to fail
**/ (lines:149-152; file:/Users/kris/Desktop/Testable.php)
Test: TestTwo was a success 



5> PartialOrder..:

获取PHPUnit.这是非常容易使用.

然后从非常简单的断言开始.在进入其他任何事情之前,您可以使用AssertEquals进行大量操作.这是让你的脚湿润的好方法.

您可能还想先尝试编写测试(因为您提出了TDD标记的问题),然后编写代码.如果你没有这样做之前它是一个大开眼界.

require_once 'ClassYouWantToTest';
require_once 'PHPUnit...blah,blah,whatever';

class ClassYouWantToTest extends PHPUnit...blah,blah,whatever
{
    private $ClassYouWantToTest;

   protected function setUp ()
    {
        parent::setUp();
        $this->ClassYouWantToTest = new ClassYouWantToTest(/* parameters */);
    }

    protected function tearDown ()
    {
        $this->ClassYouWantToTest = null;
        parent::tearDown();
    }

    public function __construct ()
    {   
        // not really needed
    }

    /**
     * Tests ClassYouWantToTest->methodFoo()
     */
    public function testMethodFoo ()
    {
        $this->assertEquals(
            $this->ClassYouWantToTest->methodFoo('putValueOfParamHere), 'expectedOutputHere);

    /**
     * Tests ClassYouWantToTest->methodBar()
     */
    public function testMethodFoo ()
    {
        $this->assertEquals(
            $this->ClassYouWantToTest->methodBar('putValueOfParamHere), 'expectedOutputHere);
}



6> Sofia..:

对于简单的测试和文档,php-doctest相当不错,这是一个非常简单的入门方式,因为您不必打开单独的文件.想象一下下面的功能:

/**
* Sums 2 numbers
* 
* //doctest: add
* echo add(5,2);
* //expects:
* 7
* 
*/
function add($a,$b){
    return $a + $b;   
}

如果您现在通过phpdt(php-doctest的命令行运行程序)运行此文件,将运行1个测试.doctest包含在块中.Doctest起源于python,可以提供关于代码如何工作的有用且可运行的示例.你不能完全使用它,因为代码本身会乱丢测试用例,但我发现它与更正式的tdd库一起使用 - 我使用phpunit.

这第一次的答案在这里概括起来很好(这不是单元VS文档测试).

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有