модульный тест метод, который создает объект - PullRequest
4 голосов
/ 13 ноября 2009

Я пытаюсь успокоиться Модульное тестирование и мне нужно найти еще один кусок головоломки.

Я пытаюсь написать тесты для следующего кода. В этом случае у меня есть действительно простой Front Controller (написанный на PHP).

class frontController
{
   public function routeRequest($oRequest)
   {
      $sClassname = $oRequest->getController();
      $sMethod = $oRequest->getAction();

      $oController = new $sClassname();

      $oResponse = $oController->{$sMethod}($oRequest);

      return $oResponse;
   }

}

У меня проблема в том, что код создает новые объекты . Я легко могу макетировать объект запроса, чтобы я мог жестко контролировать то, что он будет фактически делать в моем тестовом примере. Я не уверен, что лучший способ на самом деле заменить контроллер на двойной тест.

В этой статье 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();
   }
}

Полагаю, что об внедрении зависимостей можно было бы позаботиться в конструкторе фронт-контроллера или через установщик вместо параметра фактического метода "route".

Мне кажется, я предпочитаю вариант 2.

Является ли любой из этих двух методов правильным способом проверки такого рода вещей?

(возможно, здесь лучше сказать "хороший путь"!)

Любые мысли или предложения по варианту 1 против варианта 2 приветствуются или вообще любые альтернативы. Помните - главное в том, как протестировать объект, который сам создает другие объекты как часть его выполнения.

Спасибо!

Ответы [ 4 ]

4 голосов
/ 15 ноября 2009

Вы можете найти эту статью удобной.

Здесь обсуждается, как создание объекта должно быть отделено от фактического запуска приложения.

2 голосов
/ 03 декабря 2009

Я обычно считаю, что фабрики - это хорошая вещь для использования в этом сценарии. В дополнение к аспекту перестановки, это означает, что дополнительные параметры, данные или зависимости, необходимые для создаваемого объекта, могут храниться на фабрике, и поэтому объект, который фактически запрашивает новый объект, не должен ничего знать о них. ..

0 голосов
/ 13 ноября 2009

Полагаю, вы продумали свои утверждения, чтобы определить цель того, что именно вы тестируете. Имейте в виду, что модульные тесты будут проверять результаты ваших методов, в данном случае это $ oResponse (что бы это ни было). В результате ваши тестовые утверждения будут основаны на этом возвращаемом значении. Так как я не знаю, что это возвращаемое значение из ваших фрагментов кода, я могу только продемонстрировать пример, который вы можете завершить.

Я бы порекомендовал PHPUnit для вашего тестирования, так как он кажется наиболее полным пакетом для PHP imho (многие также являются поклонниками SimpleTest ... каждому по своему).

Это выглядело бы примерно так (обратите внимание, что для краткости я не включил в список включенные файлы. Прочитайте документацию PHPUnit для получения дополнительной информации):

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 для метода, который возвращает этот объект после создания экземпляра.

0 голосов
/ 13 ноября 2009

Вы не хотите использовать настоящий контроллер, а издеваться, верно?

Мне кажется, самый простой способ добиться этого - создать подкласс запроса, чтобы он возвращал имя MockController.

...