Есть ли хорошие способы издеваться над конкретными методами в абстрактных классах с использованием PHPUnit?
То, что я нашел до сих пор:
Ниже приведены некоторые модульные тесты, в которых рассмотрены следующие пункты:
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 ().