В PHPUnit, как я могу издеваться над родительскими методами?
Я хочу протестировать метод класса, который вызывает родительский метод с тем же именем. Есть ли способ сделать это?
class Parent {
function foo() {
echo 'bar';
}
}
class Child {
function foo() {
$foo = parent::foo();
return $foo;
}
}
class ChildTest extend PHPUnit_TestCase {
function testFoo() {
$mock = $this->getMock('Child', array('foo'));
//how do i mock parent methods and simulate responses?
}
}
5 answers
Вы не издеваетесь и не заглушаете методы в тестируемом объекте (SUT). Если вы чувствуете, что вам нужно высмеять или заглушить метод в родительском элементе SUT, это, скорее всего, означает, что вам не следовало использовать наследование, а агрегацию.
Вы издеваетесь над зависимостями тестируемого объекта. Это означает, что любые другие объекты, необходимые SUT для выполнения работы.
Подход, который работает для меня, - это реализация переноса на родительский вызов дочернего класса и, наконец, имитация этого переноса.
Вы изменили код:
class Parent {
function foo() {
echo 'bar';
}
}
class Child {
function foo() {
$foo = $this->parentFooCall();
return $foo;
}
function parentFooCall() {
return parent::foo();
}
}
class ChildTest extend PHPUnit_TestCase {
function testFoo() {
$mock = $this->getMock('Child', array('foo', 'parentFooCall'));
//how do i mock parent methods and simulate responses?
}
}
Вот как я это сделал, я понятия не имею, правильно ли это, но это работает:
class parentClass {
public function whatever() {
$this->doSomething();
}
}
class childClass extends parentClass {
public $variable;
public function subjectUnderTest() {
$this->variable = 'whocares';
parent::whatever();
}
}
Теперь в тесте я делаю:
public function testSubjectUnderTest() {
$ChildClass = $this->getMock('childClass', array('doSomething'))
$ChildClass->expects($this->once())
->method('doSomething');
$ChildClass->subjectUnderTest();
$this->assertEquals('whocares', $ChildClass->variable);
}
Что за?
Мое рассуждение здесь заключается в том, что все, что я действительно хочу проверить, это то, установлена ли моя переменная. мне на самом деле все равно, что происходит в родительском методе, но, поскольку вы не можете запретить родительскому методу вызываться, я высмеиваю зависимые методы родительского метода.
А теперь продолжайте и скажите мне, что я ошибаюсь:)
Я полностью согласен с @Гордоном. У меня та же проблема, но я попробовал несколько хитрых концепций.
Мой сценарий похож на
class Parent { // Actual-Parent Class
function save() {
// do something
return $this
}
}
class Child extends Parent {
// Subject under test
function save() {
// do something
return parent::save();
}
}
Я создал другой родительский класс с тем же именем "Родитель" и рассматриваю его как заглушку и включаю свой класс-заглушку (родитель) и игнорирую фактического родителя (фактический родительский класс, установленный в режим автоматической загрузки, и должен быть включен заглушка-родитель)
class Parent { //Stub-Parent class
function save() {
return $this
}
}
Теперь я создаю макет объекта дочернего класса (с помощью макета-конструктора) и завершаю свои тестовые примеры с окончанием assertSame. :-)
$this->assertSame($mock, $mock->save());
Удовлетворительным решением, на мой взгляд, является создание класса, наследуемого от вашего тестируемого класса, и переопределение реализации метода, который вы хотите предоставить другой реализации. У этого есть свои недостатки: это не всегда работает, например, для уже переопределенных методов и для частных методов.
class Parent
{
function bar()
{
echo 'bar';
}
}
class Child extends Parent
{
function foo()
{
parent::bar();
echo 'foo';
}
}
class mockChild extends Child
{
function bar()
{
echo 'baz';
}
}
class ChildTest extends PHPUnit_TestCase
{
function testFoo() {
$sut = new mockChild();
$sut->foo();
}
}