【问题标题】:unit test a method that creates an object单元测试创​​建对象的方法
【发布时间】:2010-12-16 06:59:32
【问题描述】:

我正在尝试单元测试,我还需要找到一块拼图。

我正在尝试为以下代码编写测试。在这种情况下,我有一个非常简单的前端控制器(用 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 的依赖类。这样,我可以在测试期间用测试替身替换工厂/创建类。像这样的:

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();
   }
}

我猜依赖注入可以在前端控制器构造函数中处理,也可以通过设置器而不是实际“路由”方法的参数来处理。

我认为我更喜欢选项 2。

这两种方法中的任何一种都是测试这类东西的正确方法吗?

(也许“好方法”在这里会更好!)

对选项 1 与选项 2 的任何想法或建议表示赞赏,或者确实有任何替代方案。请记住 - 关键是关于如何测试一个对象本身会创建其他对象作为其执行的一部分。

谢谢!

【问题讨论】:

    标签: php unit-testing oop tdd phpunit


    【解决方案1】:

    您可能会发现this article 很方便。

    它讨论了如何将对象创建与应用程序的实际运行分开。

    【讨论】:

    • 我喜欢。 “缺失的概念”之一通常似乎是对象构建/配置与运行时之间的区别。
    【解决方案2】:

    我通常发现工厂在这种情况下是一个好东西。除了可交换性方面,这意味着正在创建的对象所需的附加参数、数据或依赖项可以由工厂存储,因此实际请求新对象的对象不必知道它们的任何信息。 ..

    【讨论】:

    • 我认为你是对的。工厂是要走的路;他们肯定有助于依赖关系(就像你说的那样)。有时我认为你最终会拥有太多的工厂,但总的来说我很高兴有这样的缺点。
    【解决方案3】:

    你不想使用真正的控制器而是一个模拟,对吧?

    在我看来,实现这一点的最简单方法是将请求子类化,以便它返回 MockController 的名称。

    【讨论】:

      【解决方案4】:

      我假设您已经仔细考虑了您的断言,以便定义您正在测试的目标。请记住,单元测试将测试您的方法的返回,在这种情况下,它是 $oResponse(无论这可能是什么)。因此,您的测试断言将基于此返回值。由于我不知道您的代码 sn-ps 的返回值是什么,所以我只能演示一个您可以完成的示例。

      我会推荐 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");
            }
      

      希望我没有完全偏离您所声明的目的。这个故事的寓意是你只能测试你的方法返回什么。如果您想从一个方法测试对象实例化,请使用 PHP 函数的 instanceof 函数来处理实例化后返回该对象的方法。

      【讨论】:

      • 我不确定在开始之前我是否确实考虑过我想要测试的内容!好建议!粗略地说,这正是我想要的。但是,您的示例也会无意中测试其他对象是否正常工作(例如:控制器)。我想我只是想隔离这个 ONE 类,我知道要做到这一点应该使用测试替身(模拟/存根)。非常方便的答案。
      猜你喜欢
      • 2011-08-23
      • 2017-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 2014-06-07
      • 1970-01-01
      相关资源
      最近更新 更多