Тестирование базы данных на PHP (PHPUnit, DbUnit)

Занимаюсь рефакторингом сервиса и решил написать для своих классов тесты. Класс самый простой, для коннекта к базе использует PDO, никаких фреймворков не задействовано. Выбор пал на PHPUnit, что, наверное, не удивительно.

Поизучал мануалов, посмотрел слайдов.

Но вот не всё понятно именно по методологии такого тестирования. Судя по тому, что я прочитал и успел накодить, нужно:

1) Завести отдельную тестовую базу
2) Набросать фикстур (я использую yaml формат)
3) Выполнить тесты

Ну а как же быть дальше? Вот допустим поменяется структура какой-либо таблицы, к примеру возьмёт барабашка и дропнет колонку `id` в таблице `users`. Запустит тесты — и всё ж замечательно, фикстуры-то прежние. То есть это геймор в виде постоянного ручного контроля? — имхо не есть гут.

И ещё увидел в презентации совет по возможности избегать тестирования бд с ипользованием серверов (акцент был сделан на скорости выполнения), а использовать mocks&stubs. Вот это хотелось бы узнать поподробнее — на основе чего их генерировать, как отслеживать изменения и прочая? Может кто сталкивался с подобной задачей, сейчас ведь все тестируют, я это чувствую :)

Заранее благодарен за любую помощь.
  • Вопрос задан
  • 7766 просмотров
Пригласить эксперта
Ответы на вопрос 4
powerman
@powerman
Systems Architect, Senior Go/Perl Linux Developer
Мне в своё время очень помогла разобраться с тестированием книжка Perl Testing: A Developer's Notebook. В подходе к тестированию особой разницы между Perl и PHP нет, так что Вам она тоже может оказаться полезна. Перевода, к сожалению, я по-быстрому не нашёл, возможно она есть только на английском.

При тестировании один из ключевых моментов — нужно постоянно очень хорошо отдавать себе отчёт в том, что именно мы сейчас тестируем. А тестируем мы обычно наш код, а не окружающую среду (вроде базы данных) — в тестах мы предполагаем, что база данных работает корректно, вопрос в том, корректно ли наш код работает с базой данных. Поэтому, да, можно тестировать работу с базой даже без самой базы — mock-нув функции отправляющие SQL-запросы в базу, и в тесте проверяя, что наш код генерирует именно те SQL-запросы, в том порядке и с теми значениями, которые он должен был сгенерировать (а заодно и подставляя тестируемому коду нужные нам данные под видом «ответа от базы на SQL-запрос»). И да, на реальной базе данных этот код может не работать корректно, не смотря на то, что тесты он проходит — просто потому, что он генерирует не те SQL-запросы, которые нужно генерировать для этого сервера БД. Но это не имеет отношения к тестам — они свою работу выполнили: подтвердили, что код работает именно так, как ожидается. А если задача была поставлена неверно, и код должен делать что-то другое — это проблема постановки задачи, а не тестирования.

Барабашка портящий базу — это не проблема тестирования кода. Хотите написать тест против барабашек — сравнивайте в тесте схему базы с эталонной, и правьте тест после любого изменения схемы базы. Но смысла в этом нет.

Совместимость фикстур из тестов с текущей схемой базы проверить очень просто: при запуске теста создавайте тестовую базу данных используя текущую схему основной базы данных, а в фикстурах храните только данные, без схемы таблиц.

Гемор с необходимостью постоянно поддерживать и корректировать тесты для совместимости с новым кодом — он есть, и его не может не быть. Но усилия, которые на это тратятся, с лихвой окупаются пользой от наличия тестов.
Ответ написан
Комментировать
@noRerih Автор вопроса
Спасибо за подробный ответ.

По поводу автоматической генерации и сравнения схем — об этом я тоже подумал, и думаю смысл всё же в этом есть. Ещё можно фикстуры генерить автоматически, основываясь на данных рабочей базы, потому что протестировать нужно очень много случаев, и необходимо чтобы различные связи между данными таблиц были соблюдены. Например есть пользователи и их посты. Нужно обязательно чтобы в фикстурах были юзеры, у которых есть один пост, несколько, ни одного. Конечно, при первичном формировании таких данных будет использоваться текущий, то бишь не протестированный код, но в принципе должно получиться.

Но всё равно главное осталось мне неясным :(( Задача стоит протестировать не код, а работу сервиса, и то, что сервис обращается к БД, как раз дело и усложняет («предпологаем что бд работает корректно» — она-то так и работает, mysql отлаживают другие люди, а вот какие туда вызовы поступают — уже моя ответственность). Какие есть способы протестировать работу с базой без задействования базы? Какие именно данные нужно mock'нуть и где что проверять?

вот есть например такой класс
<?php
// file app/User.php
  class User {
  ...
  public function create($params) {
    $this->pdo->prepare("INSERT INTO `users` ...");
    $this->pdo->execute($params);
  }
}


И тест
<?php
// file tests/TestUser.php
 function testUserIsCreatedSuccessfully() {
    ...
   $user->create(array('firstname'= > 'John', 'lastname' => 'Doe'));
   ...
   $this->assertTablesEqual($expectedTable, $queryTable);
  }


Как именно и что нужно мокапить в функции, тестирующей добавление пользователя? Значит ли это, что нужно править тестируемый метод, чтобы он не в бд ещё писал, а делал нечто другое? Ведь, так или иначе, в коде теста вызывается тестируемый метод, пишущий в базу. Как узнать, что он корректно отработал, не обращаясь к БД?
Ответ написан
В дополнение к powerman
Я могу выделить такие ситуации:
1) тест функционала или классов, не имеющих сильной зависимости от внешних сервисов
2) тоже самое, но со слишком обширным использованием DAO
3) интеграционные тексты

В первом случае можно спокойно мокировать запросы в БД или иные внешние сервисы.
Во втором случае по возможности использую обертывание в транзакцию и откат в самом конце теста (методы setUp и tearDown). Если нельзя, то тоже самое что в п.3
В третьем случае делается всё «на живую» в девелоперской среде или использовать тестовую базу и естественно иметь скрипт генерирующий окружение.
Ответ написан
Комментировать
@ivanfree3
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы