Вымысел конкретного метода в абстрактном классе с использованием phpunit

Есть ли хорошие способы издеваться над конкретными методами в абстрактных классах с использованием PHPUnit?

То, что я нашел до сих пор:

  • expects () -> will () отлично работает с использованием абстрактных методов
  • Это не работает для конкретных методов. Вместо этого выполняется исходный метод.
  • Использование mockbuilder и предоставление всех абстрактных методов и конкретного метода setMethods () работает. Однако для этого требуется указать все абстрактные методы, сделав тест хрупким и слишком подробным.
  • MockBuilder :: getMockForAbstractClass () игнорирует setMethod ().

Ниже приведены некоторые модульные тесты, в которых рассмотрены следующие пункты:

abstract class AbstractClass { public function concreteMethod() { return $this->abstractMethod(); } public abstract function abstractMethod(); } class AbstractClassTest extends PHPUnit_Framework_TestCase { /** * This works for abstract methods. */ public function testAbstractMethod() { $stub = $this->getMockForAbstractClass('AbstractClass'); $stub->expects($this->any()) ->method('abstractMethod') ->will($this->returnValue(2)); $this->assertSame(2, $stub->concreteMethod()); // Succeeds } /** * Ideally, I would like this to work for concrete methods too. */ public function testConcreteMethod() { $stub = $this->getMockForAbstractClass('AbstractClass'); $stub->expects($this->any()) ->method('concreteMethod') ->will($this->returnValue(2)); $this->assertSame(2, $stub->concreteMethod()); // Fails, concreteMethod returns NULL } /** * One way to mock the concrete method, is to use the mock builder, * and set the methods to mock. * * The downside of doing it this way, is that all abstract methods * must be specified in the setMethods() call. If you add a new abstract * method, all your existing unit tests will fail. */ public function testConcreteMethod__mockBuilder_getMock() { $stub = $this->getMockBuilder('AbstractClass') ->setMethods(array('concreteMethod', 'abstractMethod')) ->getMock(); $stub->expects($this->any()) ->method('concreteMethod') ->will($this->returnValue(2)); $this->assertSame(2, $stub->concreteMethod()); // Succeeds } /** * Similar to above, but using getMockForAbstractClass(). * Apparently, setMethods() is ignored by getMockForAbstractClass() */ public function testConcreteMethod__mockBuilder_getMockForAbstractClass() { $stub = $this->getMockBuilder('AbstractClass') ->setMethods(array('concreteMethod')) ->getMockForAbstractClass(); $stub->expects($this->any()) ->method('concreteMethod') ->will($this->returnValue(2)); $this->assertSame(2, $stub->concreteMethod()); // Fails, concreteMethod returns NULL } } 

Я переопределяю getMock() в моем базовом тестовом примере, чтобы добавить все абстрактные методы, потому что вы все равно должны их издеваться над ними. Без сомнения, вы могли бы сделать что-то подобное с строителем.

Важно: вы не можете издеваться над частными методами.

 public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) { if ($methods !== null) { $methods = array_unique(array_merge($methods, self::getAbstractMethods($originalClassName, $callAutoload))); } return parent::getMock($originalClassName, $methods, $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload); } /** * Returns an array containing the names of the abstract methods in <code>$class</code>. * * @param string $class name of the class * @return array zero or more abstract methods names */ public static function getAbstractMethods($class, $autoload=true) { $methods = array(); if (class_exists($class, $autoload) || interface_exists($class, $autoload)) { $reflector = new ReflectionClass($class); foreach ($reflector->getMethods() as $method) { if ($method->isAbstract()) { $methods[] = $method->getName(); } } } return $methods; } 

Был запрос Pull для этого 2 года назад, но информация никогда не была добавлена ​​в документацию: https://github.com/sebastianbergmann/phpunit-mock-objects/pull/49

Вы можете передать свой конкретный метод в массиве в аргументе 7 getMockForAbstractClass ().

См. Код: https://github.com/andreaswolf/phpunit-mock-objects/blob/30ee7452caaa09c46421379861b4128ef7d95e2f/PHPUnit/Framework/MockObject/Generator.php#L225