2013-08-10 2 views
2

Я пытаюсь использовать TDD для класса, который управляет подключениями к базе данных. ОднакоInstance mocking и implicit constructors

  • Я часто развивается от сети, где базы данных доступны
  • Я хочу просто проверить классы не возиться с реальными связями, даже SQLite :memory:
  • я могу хотеть, чтобы проверить соединения в платформенно-независимом режиме (например, обмен объектами PDO для объектов MySQLi и т. д.). Тем более, что базы данных не все MySQL, некоторые из них - SQLServer.

По существу я хочу сделать это:

class ConnectionManager { 
    ... 
    public function getConnection($name) { 
     $params = $this->lookup($name); 
     return new \PDO($params['spec'], $params['username'], $params['password']); 
    } 
} 

И в моем тестовом бегуна:

class ConnectionManagerTest extends \PHPUnit_Framework_TestCase { 
    public function testGetConnection() { 
     $cxn = new ConnectionManager(); 
     $this->assertNotNull($cxn->getConnection('test')); // or whatever 
    } 
} 

Как-то я хотел бы использовать макет класса PDO. Является ли мой единственный вариант добавить явный параметр в конструктор тестового класса или один из его методов? Я пробовал использовать «Экземпляр издевательства» в соответствии с документацией Mockery, но поскольку я использую автозагрузку, которая приводит к «фатальной ошибке, не может переопределить класс» (duh).

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

Спасибо за вашу помощь

+0

Менеджер соединений всегда (и только) возвращает 'PDO'. Итак, вам, вероятно, нужен другой менеджер соединений, поскольку ваш тест теперь получился? – hakre

+0

На самом деле проблема диспетчера подключений несколько менее важна, так как PDO поддерживает несколько разных типов соединений. Основная проблема заключается в том, что реальные соединения недоступны при разработке вне сети.И мне, возможно, придется сложить эти «простые старые объекты PHP» в структуру позже, но я еще не знаю, что, поэтому я хотел бы быть как можно скорее агностиком-реализацией – excatholica

+0

Ну, я только ткнул из-за имени. Если вам нужна эта работа, Create 'class ConnectionManagerStub расширяет ConnectionManager', а затем меняет те, которые вам нужны, чтобы проверить, чтобы зависимости исчезли, сохраняя заглушку для совместной работы, например. для ваших тестов вообще не используется какой-либо PDO (или один в памяти, а какой нет). – hakre

ответ

3

Это похоже на случай, когда инъекции зависимости могут помочь вам. В Интернете есть много хороших статей, описывающих этот метод (вот wikipedia overview), и этот предыдущий stack overflow answer дает краткое объяснение этой методики (пример представлен на Java, но он должен объяснить шаблон и быть легко переносимым на другой язык).

Ваш вопрос о том, что «не хочет загрязнять код контрактами, чисто используемыми для тестирования», является интересным. То, что, как я думаю, вы найдете, по мере того, как вы получите больше опыта работы с TDD, заключается в том, что написанный код, который должен легко тестироваться и писать хороший чистый код, по существу является двумя сторонами одной и той же монеты. Одна из тонких возможностей TDD (когда правильная практика) заключается в том, что она ведет вас к хорошему, чистому дизайну, который можно легко вырастить с помощью вашего приложения. Следуя подходу, который ставит тестирование в основу разработки кода, вы на самом деле разрабатываете код с точки зрения клиента, что приводит к более чистым интерфейсам к различным компонентам вашего кода и в конечном итоге делает код, который использует эти интерфейсы более чистым.

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

+0

DI - это, безусловно, возможность, но сложно реализовать на PHP. Как правило, вам нужна инфраструктура с контейнером IoC или еще что-то вроде [Symfony2] (http://symfony.com/doc/current/components/dependency_injection/index.html) или [Laravel] (http: //four.laravel. ком/Docs/КИО). Я надеюсь использовать Laravel на треке, но в настоящее время не могу его рассмотреть. Поэтому я использую «POPOs» (Plain Old PHP Objects) как можно больше и доказываю, что приложение работает с TDD задолго до захвата контейнера и фреймворка. – excatholica

+0

Возможно, добавьте, что ваш последний комментарий об изменении технологии источников данных также имеет значение, поскольку платформа, с которой я работаю, включает компонент SaaS, для которого некоторые транзакции, в частности записи, доступны только через службы REST. Еще одна причина для того, чтобы сохранить код как агрегированный источник данных. – excatholica

+0

А интересно - не понимал, что язык будет таким разным. W.R.T должен использовать структуру IoC - возможно, вы можете имитировать DI по-разному в PHP. Например, вы можете просто назначить объект PDO переменной в тестируемом классе, а затем использовать [Setter Injection] (http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter -инъекция /), чтобы ввести макетную версию для тестирования (или просто просто назначить макет объекта переменной) – robjohncox