Модульное тестирование Zend Controller и Mocking некоторых выполненных действий - PullRequest
5 голосов
/ 29 марта 2012

Я пишу некоторые модульные тесты (PHPUnit 3.6) для своих контроллеров и хочу убедиться, что выполняются правильные действия и т. Д. Это достаточно просто. Однако некоторые контроллеры также выполняют определенные действия с помощью нежелательных моделей, таких как вставка записей в базу данных.

Я знаю, что мне нужно над ними издеваться, но неясно, как это сделать. Взяв следующий пример контроллера (вырублено для ясности):

public function addAction()
{
    $data = $this->getRequest()->getPost();
    $model = $this->getModelFactory()->getCompetitionModel()->insert($data);    }

}

Обратите внимание, все, что я хочу сделать, это убедиться, что правильный контроллер и действие были отправлены, но не хотят, чтобы запись была вставлена. Также у меня есть эквиваленты для удаления и т. Д. Я не хочу, чтобы записи действительно удалялись.

Что на самом деле нужно здесь издеваться? Модель соревнования, адаптер базы данных или фабрика моделей, или все три? Как мне их ввести? Я пытался (снова сокращен для краткости):

public function testAddActionIsDispatched()
{
    $this->request->setMethod('POST');
    $this->request->setPost(array($data…));

            $modelMock = $this->getMockBuilder('Competition_Adder')
                 ->disableOriginalConstructor()
                 ->getMock();                


            $factoryMock = $this->getMockBuilder('ModelFactory')
                    ->disableOriginalConstructor()
                    ->getMock(); 

        // Configure the stub.
            $factoryMock->expects($this->any())
                ->method('getCompetitionModel')
                ->will($this->returnValue($modelMock));        

            $modelMock->expects($this->once())
                    ->method('insert')
                    ->will($this->returnValue(true));

            $this->dispatch('/mymodule/add/');
            $this->assertController('test');
            $this->assertAction('add');  
            $this->assertResponseCode(200);
}

}

Насколько я понимаю, PHPUnit волшебным образом заменял любые ссылки на оригиналы с помощью макетов, так что при вызове отправки вместо них использовались поддельные макеты. Этого не происходит Может кто-нибудь уточнить, как это достигается?

Ответы [ 2 ]

3 голосов
/ 01 апреля 2012

Похоже, ваши макеты настроены правильно.Я на самом деле не знал, что вы можете возвращать mocks из mocks, пока я не увидел ваш вопрос и немного его не изучил.

Здесь происходит то, что вам нужно заставить метод getModelFactory () возвращать экземпляр вашей фабрики mock,Прямо сейчас он просто возвращает реальную вещь.

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

Но, возможно, вам не нужно переопределять это.В моем приложении ZF я не тестирую контроллеры, но для тестирования того, что требует сохранения данных в моих моделях, я просто переключаюсь на тестовую базу данных в своем конфигурационном файле для тестирования.Я использую Doctrine1.2, поэтому я просто запускаю транзакцию в методе setUp () и откат в методе tearDown ().

Моя тестовая база данных полностью пуста, и я в основном создаю необходимые данные в каждом тестовом методе с некоторыми конкретными фабричными классами теста.Недостаток в том, что он использует много памяти.Я думаю, что он составляет около 200 МБ примерно на 140 тестах, и не все из них требуют доступа к базе данных.

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

Пример (Вы, вероятно, не используете Doctrine. Я просто иллюстрирую, как я используютранзакции и откат для поддержания моей тестовой базы данных в согласованном состоянии):

public function setUp()
{
    $this->bootstrap = new Zend_Application(
        APPLICATION_ENV, APPLICATION_CONFIG);       
    parent::setUp();
    $bootstrap = $this->bootstrap->getBootstrap();

    $this->_conn = Doctrine_Manager::connection();
    $this->_conn->beginTransaction();
}

public function tearDown()
{
    $this->_conn->rollback();        
    $this->_conn->close();    
}
0 голосов
/ 11 апреля 2012

Да, посмотрите предыдущий ответ. Я могу согласиться во всех случаях. Но то же самое не может быть реализовано с MySQL и Zend_Db. Это потому, что Zend_Db не имеет вложенных транзакций. Поэтому единственное, что вы можете сделать, это использовать тестовую базу данных и перестраивать ее после каждого теста.

Проверьте , как это делается с помощью среды тестирования Codeception с Zend Framework и модулем Db .

...