Вопрос: PHPUnit: как сохранить аргументы, переданные методу stub


Метод setValue () В классе SomeClass принимает аргументы и нет способа вернуть эти аргументы для утверждения make.

Могу ли я создать заглушку для метода setValue (), которая позволяет сохранить аргументы, переданные этому методу?


class SomeClass {
  public function setValue($name, $value)
  {
    // do some stuff
  }
  public function doSomething(array $values)
  {
    foreach ($values as $name=>$value) {
      $this->setValue($name, trim($value));
    }
  }
}

class TestSomeClass расширяет PHPUnit_Framework_TestCase {
  публичная функция testDoSomething ()   {     $ mock = $ this-> getMock ('SomeClass', array ('setValue'));     $ mock-> doSomething (array ('v1' => 'string'));     // здесь мне нужно утверждать, как это     $ this-> assertEquals ('string', $ argumentPassedToSetValue);   } }


4


источник


Ответы:


О том, как проверить, работает ли настройка, см. @Gordons.

Я хотел бы утверждать, что вы не необходимость  чтобы проверить это.

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

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

Ради аргумента, скажем, SomeClass - это то, что в итоге выплевывает HTML.

class SomeClass {
  public function setValue($name, $value)
  {
    // do some stuff
  }

  public function doSomething(array $values)
  {
    foreach ($values as $name=>$value) {
      $this->setValue($name, trim($value));
    }
  }

  public function createHTML() 
  {
    $return = "";
    foreach($this->values as $key => $value) { 
         $return .= "<div is='$key'>$value</div>"; 
    }
    return $return;
  }

}

Если это все, что ваш класс делает абсолютно достаточный тест для этого класса, это может выглядеть так:

class SomeClassTest extends PHPUnit_Framework_TestCase {

    public function testHtmlGenerationWithTwoValuesSet() {
        $o = new SomeClass();
        $o->setValue("foo", "bar");
        $o->setValue("x", "y");
        $result = $o->createHTML();
        $this->assertSame(
             2,
             substr_count("<div>", $result),
             "There should be as many divs as there are values set"
        );
        $this->assertTrue(
             strpos("<div>bar</div>") !== false
             "String should contain a set value enclosed in divs"
        );
    }

}

Опять же: речь идет о тестировании поведение  вашего класса, не тестировать каждый метод самостоятельно , Ваш тестовый пакет будет намного более ценным, если вы это узнаете

Хотя пример с html не может быть правильным, он показывает, как довольно хорошо проверить поведение (надеюсь)


3



Нет. Mocks  находятся замены для зависимостей  а не для фактического TestSubject.

В случае, если setValue метод устанавливает непубличные свойства, вы можете использовать assertAttributeEquals:

class SomeClass
{
    protected $foo;
    public function setFoo($val)
    {
        $this->foo = trim($val);
    }
}

class SomeClassTest extends PHPUnit_Framework_TestCase
{
    public function testSetFooTrimsArgument()
    {
        $testSubject = new SomeClass;
        $testSubject->setFoo('  bar  ');
        $this->assertAttributeEquals(
            'bar',  /* expected value */
            'foo',  /* attribute name */
            $testSubject
        );
    }
}

Более подробную информацию о том, как тестировать рядовых, можно найти в


2



Вы можете использовать returnCallback для выполнения произвольного кода, как тестовый помощник вашего тестового теста. Например, если setValueTester - это метод в вашей тестовой системе, это ожидание перенаправит вызов setValue на макет к нему. Аргументы доступны с func_get_args.

$mock->expects($this->any())->method("setValue")->will($this->returnCallback(array($this,"setValueTester"));

1



В этом простом случае вы можете указать аргумент, который вы ожидаете передать setValue(),

class TestSomeClass extends PHPUnit_Framework_TestCase
{
  public function testDoSomething()
  {
    $mock = $this->getMock('SomeClass', array('setValue'));
    $mock->expects($this->once())->method('setValue')->with('v1', 'string');
    $mock->doSomething(array('v1'=>'  string  '));
  }
}

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


1



PHPUnit: как сохранить аргументы, переданные методу stub | Programmerz.ru