我正在编写自己的测试类。我遇到的问题是测试正在测试的函数是否会抛出预期的异常。
我知道我可以这样做:
try{
tested_function($expression->beingTestedThatWillThrowAnException());
}catch ($exception){
if($exception instanceof MyExpectedException){
echo 'OK';
} else {
echo 'FAILED';
}
}
但是我希望我不必每次都写这个try ... catch
块,所以我想把它放在测试器类方法中。
但是当我做这样的事情时
class Tester {
/**
* @param mixed expression to evaluate
* @param string expected exception class name
*/
public function assertException($expression, $expectedException){
try{
$expression;
} catch ($ex) {
if(is_subclass_of($ex, $expectedException)){
echo 'OK';
} else {
echo 'FAILED';
}
}
这失败了,因为$expression
在方法调用时被评估,所以在程序进入try
块之前。
我尝试的另一种方法是使用eval
并将$expression
作为字符串传递:
class Tester {
/**
* @param string expression to evaluate
* @param string expected exception class name
*/
public function assertException($expression, $expectedException){
try{
eval($expression);
} catch ($ex) {
if(is_subclass_of($ex, $expectedException)){
echo 'OK';
} else {
echo 'FAILED';
}
}
这没关系,但是它不允许我使用主范围内的变量,所以例如这一行失败$test->assertException('$d->divideBy(0);');
因为$d
中没有Tester::assertException()
变量范围。
我应该将所有可能的变量名称声明为全局吗?
如何强制在方法中评估表达式(或以其他方式实现所需的结果)?
我知道有现成的单元测试人员(PHPUnit,SimpleTest等),但我自己也希望能够做到这一点。
答案 0 :(得分:1)
您可以将匿名函数(闭包)作为$ expression传递,并使用use
关键字将任何变量绑定到它 - http://php.net/manual/en/functions.anonymous.php
抱歉英语不好,我希望这是可以理解的。
答案 1 :(得分:1)
这不是对您的问题的直接回应,而是实现预期结果的另一种方式。
PHPUnit有一种通过使用注释来声明异常的有趣方法。我做了一个小概念证明,说明如何通过注释来完成。
我们的单元测试小框架:
/**
* for now, it is added just for Dependency Inversion Principle
*/
interface Test {}
class TestRunner
{
/**
* This method will run our tests
*
* @param array $tests
*/
static public function run(Test $testObject)
{
$reflectedClass = new ReflectionClass($testObject);
foreach ($reflectedClass->getMethods() as $reflectedMethod) {
// we test only the methods which start with 'test'
if (strpos($reflectedMethod->getName(), 'test') === 0) {
$docComment = $reflectedMethod->getDocComment();
try {
// call our method
$reflectedMethod->invoke($testObject);
} catch (Exception $exception) {
$expectedExceptions = preg_match_all(
'/(\*\s@assertException)(\s+)(?<exception_class>[^\s]*)/',
$docComment,
$matches
);
if ($matches) {
$status = 'FAILED';
if (in_array(get_class($exception), $matches['exception_class'])) {
$status = 'OK';
}
printf("test '%s' status: %s\n", $reflectedMethod->getName(), $status);
} else {
throw $exception;
}
}
}
}
}
}
和我们的测试:
class MyCustomException extends Exception {}
class MyTest implements Test
{
/**
* @assertException MyCustomException
*/
public function testMe()
{
// replace this with your expression
// which should trow the exception
throw new MyCustomException();
}
}
TestRunner::run(new MyTest());