PHPUnit自定义断言需要帮助

7
我正在尝试向phpunit添加自定义断言,按照这个教程的步骤进行操作,以验证作为字符串返回的复数(例如

"-123+456i"

由我测试的方法)对于实部和虚部都具有预定义精度。 我已经编写了一个Complex.php类来解析字符串为实部和虚部,并组合了以下断言类作为complexAssert.php:

require_once 'PHPUnit/Framework/Assert.php';
include_once getcwd().'/custom/Complex.php';

class complexAssert extends PHPUnit_Framework_Assert {

    public function assertComplexEquals($expected, $actual, $message = '', $delta = 0)
    {
        $expectedComplex = new Complex($expected);
        $actualComplex = new Complex($actual);

        if (!($actualComplex->getReal() >= ($expectedComplex - $delta) &&
            $actualComplex->getReal() <= ($expectedComplex + $delta))) {
            return $this->fail($message);
        }

        if (!($actualComplex->getImaginary() >= ($expectedComplex - $delta) &&
            $actualComplex->getImaginary() <= ($expectedComplex + $delta))) {
            return $this->fail($message);
        }

    }
}

我的单元测试脚本:

require_once getcwd().'/custom/complexAssert.php';
require_once 'testDataFileIterator.php';

class EngineeringTest extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider providerIMSUM
     */
    public function testIMSUM()
    {
        $args = func_get_args();
        $expectedResult = array_pop($args);
        $result = call_user_func_array(array('PHPExcel_Calculation_Engineering','IMSUM'),$args);
        $this->assertComplexEquals($expectedResult, $result);
    }

    public function providerIMSUM()
    {
        return new testDataFileIterator('rawTestData/Calculation/Engineering/IMSUM.data');
    }
}

当我只是使用assertEquals时,单元测试没有出错(但失败)…但现在我已经添加了include并改为新的assert,它崩溃了,声称无法调用未定义的方法assertComplexEquals()。

有没有人成功扩展phpunit来自定义assert,并且能看出我的错误在哪里?


你最好遵循官方的http://www.phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.custom-assertions。 - zerkms
2
虽然与此问题无关,但您可能希望使用__DIR__(PHP 5.3+)或dirname(__FILE__)而不是依赖于在程序运行时可以更改的当前工作目录。 - David Harkness
@David Harkness:我敢打赌,在他的情况下,getcwd() != __DIR__ - zerkms
@zerkms - 这很有可能,但使用 getcwd() 的危险在于它可能会因环境(测试与生产)而改变,然而包含其他模块通常需要在任何活动环境下工作。最好依赖于当前脚本的位置或包含路径与自动加载。 - David Harkness
@David Harkness:是的,但目前 OP 也依赖于他的新断言(这是库的一部分)和他的复数实现(实际上是应用程序的一部分)的相对位置。这也不是一个好的事情。 - zerkms
我已经开始使用__DIR__而不是getcwd(),但这并不是我的问题的原因...Complex和complexAssert类已经成功地被包含了,但是在PHPUnit_Framework_TestCase类的上下文中却无法使用assertComplexEquals()方法...我仍然只能访问标准的“内置”断言方法。 - Mark Baker
2个回答

1

显然,让$this->someCustomAssertion工作的唯一方法是扩展PHPUnit_Framework_TestCase并在那里创建包装器方法,或静态调用您的自定义断言。

例如,Zend Framework只是通过附加方法(断言)来扩展PHPUnit_Framework_TestCase


0
最终,我选择不扩展现有的断言,而是修改我的复杂断言逻辑,返回一个简单的布尔值,然后使用assertTrue()进行测试,并使用一个简单的getMessage()来检索错误消息以在phpunit结果中显示。老实说,这种方式使用起来感觉更加容易。
include_once __DIR__.'/Complex.php';

class complexAssert {

    private $_errorMessage = '';

    public function assertComplexEquals($expected, $actual, $delta = 0)
    {
        $expectedComplex = new Complex($expected);
        $actualComplex = new Complex($actual);

        if ($actualComplex->getReal() < ($expectedComplex->getReal() - $delta) ||
            $actualComplex->getReal() > ($expectedComplex->getReal() + $delta)) {
            $this->_errorMessage = 'Mismatched Real part: ' .
                                   $actualComplex->getReal() . 
                                   ' !== ' . 
                                   $expectedComplex->getReal();
            return FALSE;
        }

        if ($actualComplex->getImaginary() < ($expectedComplex->getImaginary() - $delta) ||
            $actualComplex->getImaginary() > ($expectedComplex->getImaginary() + $delta)) {
            $this->_errorMessage = 'Mismatched Imaginary part: ' .
                                   $actualComplex->getImaginary() . 
                                   ' !== ' . 
                                   $expectedComplex->getImaginary();
            return FALSE;
        }

        return TRUE;
    }

    public function getErrorMessage() {
        return $this->_errorMessage;
    }
}

我的单元测试脚本:

//  Custom assertion class for handling precision of Complex numbers
require_once __DIR__.'/../../custom/complexAssert.php';
//  Data Provider handler
require_once 'testDataFileIterator.php';

class EngineeringTest extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider providerIMSUM
     */
    public function testIMSUM()
    {
        $args = func_get_args();
        $expectedResult = array_pop($args);
        $result = call_user_func_array(array('PHPExcel_Calculation_Engineering','IMSUM'),$args);
        $complexAssert = new complexAssert();
        $this->assertTrue($complexAssert->assertComplexEquals($expectedResult, $result, 1E-8),
                          $complexAssert->getErrorMessage());
    }

    public function providerIMSUM()
    {
        return new testDataFileIterator('rawTestData/Calculation/Engineering/IMSUM.data');
    }
}

而且记录的phpunit结果已经足够清晰明了:

3) EngineeringTest::testIMSUB with data set #7 ('-12.34-5.67i', '-123.45-67.89', '#NUM!')
Mismatched String: 111.11 !== #NUM!
Failed asserting that false is true.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接