Reputation: 212502
I'm trying to add a custom assert to phpunit, following this tutorial, to validate complex numbers returned as a string (e.g.
"-123+456i"
by the method that I'm testing) to a defined precision for both the real and imaginary components. I've put a Complex.php class to parse the string into the real and imaginary parts, and put together the following assertion class as 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);
}
}
}
My unit test script:
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');
}
}
The unit tests worked without error (but failed) when I was simply doing an assertEquals... but now I've added the include and changed to my new assert, it's crashing claiming that it can't call the undefined method assertComplexEquals().
Has anybody had any success extending phpunit with custom asserts, and can see what I'm doing wrong?
Upvotes: 7
Views: 2035
Reputation: 212502
In the end, I chose not to extend existing asserts, but to modify my complex assertion logic to return a simple boolean, that could then be tested using assertTrue(), and with an error message that could be retrieved with a simple getMessage() for display in the phpunit results. To be honest, it feels a whole lot easier to use this way
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;
}
}
My unit test script:
// 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');
}
}
and the logged phpunit result is clear enough:
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.
Upvotes: 0
Reputation: 255065
Obviously the only way to get $this->someCustomAssertion
worked is to extend PHPUnit_Framework_TestCase
and create wrapper-methods there, or call your custom assertions statically.
Zend Framework, for example, just extends PHPUnit_Framework_TestCase
with additional methods (assertions)
Upvotes: 1