PHPUnit - циклические зависимости - PullRequest
1 голос
/ 15 февраля 2012

У меня есть класс, который выглядит примерно так:

class Foo {
    protected $_arr = array();

    public function has($key) {
        return array_key_exists($key, $this->_arr);
    }

    public function add($key, $val) {
        $this->_arr[$key] = $val;
    }
}

Для моих тестов PHPUnit для этих методов единственный способ, которым я могу думать, если проверять add(), это утверждать, что has() возвращаетTRUE для того же ключа после добавления.Это делает мой testAdd() тест зависимым от моего testHas() теста.И наоборот, единственный способ, которым я могу придумать, чтобы проверить has(), в основном состоит в том, чтобы делать те же самые шаги, но это сделало бы этот тест зависимым от уже зависимого теста, создавая проблему типа курица и яйцо.

AmЯ собираюсь об этом неправильно?Какой лучший метод для тестирования подобных вещей?

Ответы [ 4 ]

2 голосов
/ 15 февраля 2012

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

class FooTest extends PHPUnit_Framework_TestCase
{
    function testStartsEmpty() {
        $foo = new Foo;
        self::assertFalse($foo->has('bar'));
    }

    function testAddStoresKeys() {
        $foo = new Foo;
        $foo->add('bar', 'baz');
        self::assertTrue($foo->has('bar'));
    }

    function testAddStoresKeysWithNullValues() {
        $foo = new Foo;
        $foo->add('bar', null);
        self::assertTrue($foo->has('bar'));
    }

    function testAddStoresValues() {
        $foo = new Foo;
        $foo->add('bar', 'baz');
        self::assertEquals('baz', $foo->get('bar'));  // fatal error
    }
}

Теперь, когда testAddStoresValues ​​() завершается неудачно, пришло времяреализовать метод для получения значения для данного ключа: Foo::get($key).

1 голос
/ 14 марта 2012

В отношении длинных рассуждений в комментариях к ответу @ Гордона:

Единицей в модульном тестировании является объект, а не метод! Вы не хотите тестировать методы изолированно от других методов объектов. (Если вы хотите сделать это, просто используйте функции;)) - Очень важно проверить, как ведет себя объект, и думает ли он о том, как он работает, а не о том, как методы взаимодействуют внутри.

Я недавно написал сообщение в блоге, объясняющее, почему важно не тестировать отдельные методы в отдельности:

http://edorian.posterous.com/the-unit-in-unit-testing

Цитата из моего поста:

Модульное тестирование в PHP - это тестирование наблюдаемого поведения класса

Самое главное:

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


Взять этот образец:

public function setValue($value) {
    $this->value = $value;
}

public function execute() {
    if (!$this->value) {
        throw new Exception("No Value, no good");
    }
    return $value * 10; // business logic
}

Это звучит тривиально, но различие важно и его легче не заметить, глядя на большие классы.

Что мы там тестируем?

  • ЕСЛИ мы не устанавливаем значение и затем не выполняется вызов, возникает исключение!
  • ЕСЛИ мы ДЕЛАЕМ setValue И затем вызываем execute, мы получаем вычисленный результат

Итак, мы тестируем два поведения вашего класса, а не отдельные методы!

1 голос
/ 15 февраля 2012

PHPUnit позволяет тестировать непубличные члены .

Тем не менее, использование $sut->has() для определения того, сработал ли $sut->add(), вполне нормально. Кроме того, когда вы тестируете $sut->add(), вам не нужно писать отдельный тест для $sut->has(), потому что он уже описан в тесте $sut->add(). Просто добавьте аннотацию @covers.

0 голосов
/ 15 февраля 2012

ИМО вы можете проверить поведение объекта.Таким образом, вы можете проверить, было ли возвращено false до и true после добавления некоторых вещей в коллекцию.

...