PHPUnit Test Question - Как провести модульное тестирование моего класса - PullRequest
13 голосов
/ 20 января 2010

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

Мой класс, Image, используется совместно с некоторыми другими для манипулирования изображениями.

Image по существу оборачивает ресурс изображения GD и сохраняет вместе с ним данные. Например, экземпляр Image всегда будет содержать свое текущее состояние, то есть его новую ширину / высоту при изменении размера, данные исходного изображения и т. Д.

Класс Image также содержит методы для,

  • Создание себя из файла, строковых данных или URL, например, $image->loadFromPath()
  • Создание нового ресурса изображения GD из свойств текущего экземпляра Image, например, для изменения размера изображения для сохранения прозрачности фона и т. д.
  • Клонирование ресурса изображения GD для использования в классах манипуляции

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

  1. Напишите тест для каждого метода класса . Я где-то читал, что я должен проверить каждый метод. Тем не менее, некоторые из методов запускают другие (правильно, я могу добавить), поэтому у вас есть цепочка зависимостей. Но я также читал, что каждый модульный тест должен быть независимым от другого. Так что мне делать, если это так?
  2. Напишите каждый тест как маршрут использования класса . Я также где-то читал, что каждый тест должен представлять собой 1 путь / маршрут использования, который вы можете пройти с классом. Поэтому, если вы охватите каждое использование, вы в конечном итоге получите полное покрытие кода.

Итак, что из этого правильно, если есть?

Ответы [ 3 ]

9 голосов
/ 20 января 2010

Должны быть написаны юнит-тесты для оценки открытого интерфейса класса. Ваш тестовый пример должен использовать класс так, как вы собираетесь использовать в своей программе. Идея здесь состоит в том, чтобы проверить поведение (ожидаемые, неожиданные или граничные условия) класса.

Обе идеи, которые вы опубликовали, верны. Теоретически у вас должно быть достаточно тестов (маршрутов через ваш код) для запуска всех ваших методов в классе.

Как уже упоминалось, 100% тестирование - хорошая цель, но не всегда реалистичная.

Также, в случае с GD, будьте осторожны при написании модульных тестов, которые проверяют функциональность GD (он уже был протестирован, вам не нужно тратить время на его повторное тестирование). Я бы прочитал с использованием насмешек и заглушек PHPUnit (и насмешек над файловой системой) в руководстве по PHPUnit.

Вот как может выглядеть пример теста:

public function testImageIsResized()
{
    $image = new Image();
    $image->loadFromPath('some/path');
    $image->resize(200, 300);
    $this->assertEquals(200, $image->getWidth());
    $this->assertEquals(300, $image->getHeight());
}

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

5 голосов
/ 20 января 2010

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

/**
 * @test
 * @covers MyClass::something()
 * @covers MyClass::_somethingElse()
 */
public function somethingWorksAsExpected()
{
    $this->assertSame($expected, $this->testObject->something());
}

Для личных проектов 100% покрытия кода в порядке. Тем не менее, я видел выступления на конференциях, где 100% сомневались в необходимости. Несмотря на все преимущества, тестирование требует времени для написания, и в бюджетном проекте может быть достаточно просто протестировать 80/20 и исключить некритические функции вашего приложения с низким приоритетом.

Что касается того, как протестировать свой класс, ознакомьтесь с главой Разработка на основе поведения в руководстве по PHPUnit . В вашем случае я бы протестировал функционал, который вы описали в своем вопросе.

0 голосов
/ 26 мая 2011

Стивен Мелроуз сказал:

Однако некоторые методы запускаются другие (правильно я могу добавить), так что вы тогда есть цепь зависимости. Но я также прочитайте, что каждый модульный тест должен быть независимым от других

Независимость теста заключается не в том, чтобы не тестировать один и тот же код дважды, а в том, влияет ли результат (или отсутствие результата) одного теста на результат другого. Если ваш первый тест вставляет некоторые данные, а затем терпит неудачу, прежде чем он может удалить эти данные, ваш второй тест может получить результаты, отличные от ожидаемых. В идеале вы должны иметь возможность запускать свои тесты в произвольном порядке или выполнять одни, а не другие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...