public function thisMethod { $example = $this->methodReturnsObject()->this1->that2->there3->id; return $example; }
Как бы вы протестировали этот метод в PHPUnit?
Очевидно, я мог бы написать, что методReturnsObject () вернет что-то … но что? У этого объекта есть свойства, связанные с ним, но как бы вы даже издевались над этим значением?
Ответ «Ты не делаешь». Тестирование модулей должно тестировать каждый класс отдельно, то, что вы пытаетесь сделать, не является единичным тестом. Как я сказал в своем комментарии, вы нарушаете Закон Деметры , в котором просто говорится:
У вас есть тесно связанные классы, которые нуждаются в повторном факторинге. Сначала я написал классы, чтобы проиллюстрировать этот момент, но я обычно пишу тесты в первую очередь.
Давайте начнем с конца цепочки: –
class there3 { private $id public function setId($id) { $this->id = $id; } public function getId() { return $this->id; } }
Теперь давайте создадим для него единичный тест: –
class there3Test extends PHPUnit_Framework_TestCase { public function testCanGetId() { $there3 = new there3(); $there3->setId(3); $this->assertTrue($there3->getId() === 3); } }
Этот класс теперь протестирован, поэтому нам не нужно его снова тестировать. Теперь давайте посмотрим на следующий: –
class this2 { public $there3; //To facilitate unit testing we inject the dependency so we can mock it public function __construct(there3 $there3) { $this->there3 = $there3; } public function getId() { return $this->there3->getId(); } }
И теперь единичный тест: –
class this2Test extends PHPUnit_Framework_TestCase { public function testCanGetId() { $mockThere3 = $this->getMock('there3'); $mockThere3->method('getId') ->will($this->returnValue(3); $this2 = new this2($mockThere3);//We pass in the mock object instead of the real one $this->assertTrue($this2->getId() === 3); } }
Мы сделаем последний пример, чтобы еще раз проиллюстрировать мою мысль:
class this1 { private $this2; public function __construct(this2 $this2)//injecting again { $this->$this2 = $this2; } public function getId() { return $this->$this2->getId(); } }
И, опять же, единичный тест: –
class this1Test extends PHPUnit_Framework_TestCase { public function testCanGetId() { $mockThis2 = $this->getMock('this2'); $mockThis2->method('getId') ->will($this->returnValue(3); $this1 = new this1($mockThis2);//We pass in the mock object instead of the real one $this->assertTrue($this1->getId() === 3); } }
Надеюсь, вы получите идею без меня, чтобы пройти через все объекты в вашем примере.
То, что я сделал, – это отделить классы друг от друга. Они знают только об объекте, от которого они зависят, им все равно, как этот объект получает запрошенную информацию.
Теперь вызов id будет выглядеть примерно так:
public function getId() { return $this->this1->getId(); }
Который пойдет вверх по цепочке, пока не вернется id2: id. Вам никогда не придется писать что-то вроде $ this -> $ this1 -> $ this2-> there3-> id, и вы можете правильно тестировать свои классы.
Для получения дополнительной информации об модульном тестировании см. Руководство PHPUnit .
Как бы вы протестировали thisMethod в PHPUnit, я бы:
Такие как:
<?php // an opaque known $random = rand(); // the results $value = new stdClass(); $value->this1 = new stdClass(); $value->this1->this2 = new stdClass(); $value->this1->this2->there3 = new stdClass(); $value->this1->this2->there3->id = $random; // somehow get the known value into the fixture // not enough detail shown about $this->methodReturnsObject() // to make a reasonable suggestion about it. $this->assertEquals( $random, $this->fixture->thisMethod(), "Got a value from somewhere else" );
Используйте метод rrehbein для построения возвращаемого значения из метода макета и создания частичного макета любого класса, содержащего thisMethod
и methodReturnsObject
– methodReturnsObject
класс. Mock methodReturnsObject
чтобы вернуть созданный объект $value
.
Предполагая, что класс называется Foo
дает
function testThisMethod() { $foo = $this->getMock('Foo', array('methodReturnsObject')); $value = // create as rrehbein demonstrated $foo->expects($this->once()) ->method('methodReturnsObject') ->will($this->returnValue($value)); self::assertSame($value, $foo->thisMethod()); }