PHPunit 方法预计调用 1 次,实际调用 0 次
PHPunit method expected to be called 1 time, actually called 0 times
我已经被困在这个问题上一段时间了,我不确定为什么 PHPunit 看不到函数正在被调用。
这是我要测试的代码:
public function handle()
{
$path = $this->request->getPath();
$requestMethod = $this->request->getMethod();
if (!$path) {
$this->redirect('home');
} else if (!$this->isMethodPathFound($path, $requestMethod)) {
$this->redirect('404');
} else {
$handler = $this->getControllerFullName($this->routes[$path]['handler']);
if (is_callable($handler)) {
call_user_func($handler);
} else {
$this->redirect('404');
}
}
}
/**
* @param string $path
* @param int $statusCode
*/
public function redirect($path, $statusCode = 303)
{
if (defined('TESTING_ENVIRONMENT') && TESTING_ENVIRONMENT) {
return;
}
header(
'Location: ' . $this->request->getProtocol() .
$this->request->getHost() . '/' . $path,
true,
$statusCode
);
die();
}
TESTING_ENVIRONMENT 变量是为 header 函数设置的,因此它不会在 运行 PHPunit 上触发(我不想创建另一个 class该重定向功能只是为了能够模拟它进行一次测试)这是测试代码:
public function testHandlePathIsEmpty()
{
$requestMock = $this->getMockBuilder('\services\Request')->getMock();
$requestMock->expects($this->once())->method('getPath')->willReturn('');
$requestMock->expects($this->once())->method('getMethod')->willReturn('GET');
$routerMock = $this->getMockBuilder('\services\Router')
->setConstructorArgs([$this->routes, $requestMock])
->enableProxyingToOriginalMethods()
->getMock();
$routerMock->expects($this->once())->method('redirect')
->with('asdasd')->willReturn(true);
$routerMock->handle();
}
$routerMock object 绝对应该调用 "redirect" 函数,它说它不会被调用..即使当我 var_dump/die 在函数内部时,它确实会被调用进去吧。
感谢您的帮助!
只是为了说明这一点。如果你必须模拟你想测试的 class,你的代码会很复杂,你应该考虑以另一种方式实现你的逻辑。
如何不模拟您实际测试的 class,通过传递 Request
和 Router
模拟创建新实例(路由器模拟可能没有任何逻辑,因为您不会使用它),然后在您的代码中执行以下操作:
public function handle()
{
$request = $this->request;
$path = $request->getPath();
if (!$path) {
$this->redirect('home');
} else if (!$this->isMethodPathFound($path, $request->getMethod())) {
$this->redirect('404');
} else {
$handler = $this->getControllerFullName($this->routes[$path]['handler']);
if (is_callable($handler)) {
call_user_func($handler);
} else {
$this->redirect('404');
}
}
}
在你的单元测试中,你现在可以只测试
$requestMock
->expects($this->never())
->method('getMethod');
我看到这只会涵盖未执行的第二种情况,但也可能发生第三种情况。这始终是您的代码不够干净的原因。
您应该阅读有关 KISS 和 SOLID 的内容,以使您的代码更易于测试。这个方法太复杂了,你可以正确地测试它。
虽然您犹豫是否要显示 phpunit 错误的完整输出,但您的问题很可能不是您的方法没有被调用,而是它没有按照您定义的所有期望被调用。
您的代码
$routerMock->expects($this->once())->method('redirect')
->with('asdasd')->willReturn(true);
转换为以下预期:方法 redirect
必须使用参数 'asdasd'
恰好调用一次并将 return true
.
从您的测试代码中,我没有看到 asdasd
传递给了 redirect
方法。当您删除 with
期望时,您的测试很可能会成功。
我已经被困在这个问题上一段时间了,我不确定为什么 PHPunit 看不到函数正在被调用。
这是我要测试的代码:
public function handle()
{
$path = $this->request->getPath();
$requestMethod = $this->request->getMethod();
if (!$path) {
$this->redirect('home');
} else if (!$this->isMethodPathFound($path, $requestMethod)) {
$this->redirect('404');
} else {
$handler = $this->getControllerFullName($this->routes[$path]['handler']);
if (is_callable($handler)) {
call_user_func($handler);
} else {
$this->redirect('404');
}
}
}
/**
* @param string $path
* @param int $statusCode
*/
public function redirect($path, $statusCode = 303)
{
if (defined('TESTING_ENVIRONMENT') && TESTING_ENVIRONMENT) {
return;
}
header(
'Location: ' . $this->request->getProtocol() .
$this->request->getHost() . '/' . $path,
true,
$statusCode
);
die();
}
TESTING_ENVIRONMENT 变量是为 header 函数设置的,因此它不会在 运行 PHPunit 上触发(我不想创建另一个 class该重定向功能只是为了能够模拟它进行一次测试)这是测试代码:
public function testHandlePathIsEmpty()
{
$requestMock = $this->getMockBuilder('\services\Request')->getMock();
$requestMock->expects($this->once())->method('getPath')->willReturn('');
$requestMock->expects($this->once())->method('getMethod')->willReturn('GET');
$routerMock = $this->getMockBuilder('\services\Router')
->setConstructorArgs([$this->routes, $requestMock])
->enableProxyingToOriginalMethods()
->getMock();
$routerMock->expects($this->once())->method('redirect')
->with('asdasd')->willReturn(true);
$routerMock->handle();
}
$routerMock object 绝对应该调用 "redirect" 函数,它说它不会被调用..即使当我 var_dump/die 在函数内部时,它确实会被调用进去吧。
感谢您的帮助!
只是为了说明这一点。如果你必须模拟你想测试的 class,你的代码会很复杂,你应该考虑以另一种方式实现你的逻辑。
如何不模拟您实际测试的 class,通过传递 Request
和 Router
模拟创建新实例(路由器模拟可能没有任何逻辑,因为您不会使用它),然后在您的代码中执行以下操作:
public function handle()
{
$request = $this->request;
$path = $request->getPath();
if (!$path) {
$this->redirect('home');
} else if (!$this->isMethodPathFound($path, $request->getMethod())) {
$this->redirect('404');
} else {
$handler = $this->getControllerFullName($this->routes[$path]['handler']);
if (is_callable($handler)) {
call_user_func($handler);
} else {
$this->redirect('404');
}
}
}
在你的单元测试中,你现在可以只测试
$requestMock
->expects($this->never())
->method('getMethod');
我看到这只会涵盖未执行的第二种情况,但也可能发生第三种情况。这始终是您的代码不够干净的原因。 您应该阅读有关 KISS 和 SOLID 的内容,以使您的代码更易于测试。这个方法太复杂了,你可以正确地测试它。
虽然您犹豫是否要显示 phpunit 错误的完整输出,但您的问题很可能不是您的方法没有被调用,而是它没有按照您定义的所有期望被调用。
您的代码
$routerMock->expects($this->once())->method('redirect')
->with('asdasd')->willReturn(true);
转换为以下预期:方法 redirect
必须使用参数 'asdasd'
恰好调用一次并将 return true
.
从您的测试代码中,我没有看到 asdasd
传递给了 redirect
方法。当您删除 with
期望时,您的测试很可能会成功。