2011-11-07 16 views
15

PHPUnit kullanarak soyut sınıflardaki beton yöntemleri ile uğraşmanın iyi bir yolu var mı? Bugüne kadar is buldum NePhpunit kullanarak soyut sınıfta beton yönteminin somutlaştırılması

:

  • beklediği() ->() ince Beton yöntemler için çalışmıyor
  • soyut yöntemlerle çalışır olacaktır. Orijinal yöntem yerine çalıştırılır.
  • Model oluşturucuyu kullanarak ve tüm soyut yöntemleri ve setMethods() için somut yöntemi kullanarak çalışır. Bununla birlikte, tüm soyut yöntemleri belirtmeniz, testi kırılgan ve çok ayrıntılı hale getirmeniz gerekir.
  • MockBuilder :: getMockForAbstractClass(), setMethod() öğesini yok sayar.


İşte yukarıdaki noktaları örneklemek bazı birim testler şunlardır:

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 
    } 
} 
+0

:

koduna bakınız. Ya da soyut bir test tahtası yazmak ister misiniz? – hakre

+0

Soyut sınıf, başka bir sınıfın bağımlılığıdır. Bu yüzden $ object-> concreteMethod() kullanan SomeClass :: getMyCalculatedValue() öğesini test etmek istiyorum. ConcreteMethod() 'un değişmesi ya da ayarlanması zor olabileceğinden, betonMethod()' ın dönüş değerini belirtmek istiyorum. – CheeseSucker

cevap

4

Sana zaten hepsini alay gerekir çünkü tüm soyut yöntemlerde eklemek için benim baz testi durumda getMock() geçersiz kılar. Şüphesiz inşaatçıyla benzer bir şey yapabilirsin.

Önemli: Özel yöntemlerle uğraşmak mümkün değil.

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; 
} 
+0

Bu çalışır. Özel yöntemlerle uğraşmaya ihtiyacım yok =) – CheeseSucker

+0

Bu, getMockForAbstractClass'dan nasıl farklı? – FoolishSeth

+1

@FoolishSeth PHPUnit'in önceki sürümleri, [alay etmek için ek somut yöntemleri belirtmenize izin vermedi] (https://github.com/sebastianbergmann/phpunit-mock-objects/pull/49). Her soyut yöntemi alay etmeden alaycı bir nesneyi başlatamayacağınız için, onları getMock() ve ark. –