我正试着绕过单元测试,还有一件我需要找到的拼图。
我要做的是为以下代码编写测试。在这种情况下,我有一个非常简单的前端控制器(用PHP编写)。
class frontController
{
public function routeRequest($oRequest)
{
$sClassname = $oRequest->getController();
$sMethod = $oRequest->getAction();
$oController = new $sClassname();
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
}
我遇到的问题是因为代码创建了新对象。我可以轻松模拟请求对象,以便我可以严格控制它在我的测试用例中实际执行的操作。我不确定用测试双重替换控制器的最佳方法。
This article from IBM建议使用工厂方法创建我的控制器,然后用一个用于测试的特定类覆盖它:
class frontController
{
public function routeRequest($oRequest)
{
$sMethod = $oRequest->getAction();
$oController = $this->createController($oRequest);
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
protected function createController($oRequest)
{
$sClassname = $oRequest->getController();
return new $sClassname();
}
}
然后测试可能是这样的:
class testFrontController extends frontController
{
public function setMockController($oMockController)
{
$this->oMc = $oMockController;
}
protected function createController($oRequest)
{
return $this->oMockController;
}
}
(注意这不是文章所说的,但我认为如果它这样做对我来说最有用)
另一种解决方案可能是创建另一个创建控制器的类。这将是frontController的依赖类。这样我就可以在测试过程中用test double替换工厂/创建类。像这样:
class frontController
{
public function routeRequest($oRequest, $oControllerFactory)
{
$sMethod = $oRequest->getAction();
$oController = $oControllerFactory->create($oRequest);
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
}
class controllerFactory
{
public function create($oRequest)
{
$sClassname = $oRequest->getController();
return new $sClassname();
}
}
我想依赖注入可以在前端控制器构造函数中处理,也可以通过setter而不是实际“route”方法的参数来处理。
我认为我更喜欢选项2。
这两种方法中的任何一种都是测试此类事物的正确方法吗?
(也许“好方法”会更好用!)
关于选项1与选项2的任何想法或建议表示赞赏,或者确实存在任何替代方案。记住 - 关键是如何测试一个自身创建其他对象的对象作为其执行的一部分。
谢谢!
答案 0 :(得分:4)
您可能会发现this article方便。
讨论如何将对象创建与应用程序的实际运行分开。
答案 1 :(得分:2)
我通常认为工厂在这种情况下是一件好事。除了可交换性方面,它还意味着工厂可以存储正在创建的对象所需的其他参数,数据或依赖项,因此实际请求新对象的对象不必知道任何有关它们的信息。 ..
答案 2 :(得分:0)
你不想使用真正的控制器而是模拟,对吗?
在我看来,实现这一目标的最简单方法是将请求子类化,以便返回MockController的名称。
答案 3 :(得分:0)
我假设您已经仔细考虑过您的断言,以便确定您正在测试的目标。请记住,单元测试将测试您的方法的返回,在这种情况下,这是$ oResponse(无论这可能是什么)。因此,您的测试断言将基于此返回值。由于我不知道您的代码片段的返回值是什么,因此我只能演示您可以完成的示例。
我建议PHPUnit进行测试,因为它似乎是PHP imho最完整的软件包(许多人都是SimpleTest的粉丝,以及他们自己的每个人)。
它看起来像这样(请注意我为了简洁而遗漏了包含。请阅读PHPUnit documentation以获取更多信息):
class AimTest extends PHPUnit_Framework_TestCase{
private $_controller = null;
private $_request = null;
public function setUp(){
$this->_controller = new frontController();
//what does this object's type?
$this->_request = new requestObject();
}
public function testObjectCreation(){
/*
* note, that this is only one of several assertions that could
* be made depending on the return value
*/
$return = $this->_controller->routeRequest($this->_request);
//tailor to what you expect your output to be
$this->assertTrue($return == "my expected output");
}
希望我完全没有错过你声明的目的。故事的道德是你只能测试你的方法返回的内容。如果要从方法测试对象实例化,请对实例化后返回该对象的方法使用instanceof PHP函数。