у меня есть AuthorizationUpdater
сервис, с реализацией, основанной на Учение ОРМ. Когда я закончил рабочий код и провел несколько тестов, я был вынужден покинуть свой обычный цикл TDD, не зная, как написать эти два:
Доктрина реализации AuthorizationUpdater
принять доктрину EntityManager
в своем конструкторе, который он использует для чтения и записи. Предполагается, что эти два теста проверяют, когда один из этих методов EntityManager генерирует Doctine. ORMException
, он перехватывается службой и преобразуется в исключение домена.
Мой тест является интеграционным тестом, который получает EntityManager
использовать с завода.
Создание простой подделки через фиктивный API PHPUnit (getMock('className')->method('updateStuff')->willThrow(new SomeExcetion)
не кажется хорошим в этом случае. Служба использует EntityManager
перед тем, как метод выбрасывает исключение, так что макетировать все не вариант. Это оставляет создание сложной подделки EntityManager
и частично издеваться над ним (просто метод, который должен вызвать исключение). Последнее требует предоставления реальных аргументов конструктора, к которым мой тест фактически не имеет доступа, так как эта ответственность лежит в другом пакете. Следовательно, оба подхода не являются удовлетворительными, и я предпочитаю иметь это ORMException
поведение при ловле не проверяется.
Есть ли хороший способ написать тесты, которые мне нужны? Возможность обезьяны-исправления соответствующего метода на EntityManager
экземпляр будет префектом, хотя это потребует расширение runkit.
Я использую PHP 7 и, возможно, смогу переключиться на PHP 7.1. Если вам интересно, код есть на GitHub, с соответствующими тестами, проживающими в конце DoctrineAuthorizationUpdaterTest
.
Вместо создания фиктивного объекта через фиктивный API-интерфейс PHPUnit вы можете создать прокси-класс в своем тестовом пространстве имен, который получит EntityManager
с завода в качестве параметра конструктора. Прокси-класс передает каждый вызов метода EntityManager
кроме звонков, которые должны вызвать исключение. Большинство вызовов может быть передано с помощью __call
магический метод, за исключением вызовов интерфейсных методов Doctrine\Common\Persistence\ObjectManager
, который, вероятно, придется реализовать классу Proxy (методы интерфейса не могут быть реализованы с call
).
Является ли этот прокси-класс «сложной подделкой», о которой вы говорите и хотите избежать? Тогда, может быть, вы можете использовать Библиотека издевательств и не нужно писать класс.
Других решений пока нет …