PHPunit模拟只观察

Pen*_*tal 3 php phpunit

我在理解模拟对象时遇到了一些问题.

我想要的是一个正常工作的观察者,但确保使用正确的参数调用方法.

根据我的理解到目前为止,这应该是我正在寻找的:观察员:

class Observer
{
    public function returnFooIfBar($bar)
    {
        return ($bar == 'bar') ? 'foo' : ;
    }
}
Run Code Online (Sandbox Code Playgroud)

学科:

class Subject
{
    $obs;
    __construct(Observer $dependency)
    {
        $this->obs = $dependency;
    }

    public function tradeStrings($string)
    {
        $this->obs->returnFooIfBar($string);
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

class SubjectTest
{
    public function testCallsObsMethod()
    {
        $obs = $this->getMock('Observer') ;
        $obs->expect($this->once()) 
            ->method('returnFooIfBar') 
            ->with($this->equlTo('bar')) ;

        $subj = new Subject($obs);
        $returnString= $subj->TradeStrings('bar') ;

        $this->assertEqual('foo', $returnString) ;
    }
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,这测试:

  1. Observer :: getFooIfBar被调用一次.
  2. Observer :: getFooIfBar得到字符串'bar'3.该方法按类中的定义工作,并将'foo'作为字符串返回.

据我所知,除了没有运行构造函数/自动加载之外,没有更改原始类的功能.

如果我在运行getMock()时模拟一个方法,那么模拟对象的方法只会在指定它时返回一些内容.

$obs = $this->getMock('Observer', array('returnFooIfBar'));
$obs->expects($this->once())
    ->method('returnFooIfBar')
    ->with('bar')
    ->will($this->returnValue('foo');
Run Code Online (Sandbox Code Playgroud)

我理解这个吗?如果没有,请你为我澄清一下,因为我希望对此有所了解.:)

编辑:更改帖子,使我更清楚我所追求的以及我目前如何理解它.

Jan*_*ser 7

如果让phpunit创建一个模拟对象,它会在内部构建一个新的临时类,它扩展原始的类,并使用模拟特定代码实现此类的所有方法.

这背后的想法是在测试用例中解耦对象.虽然您的给定示例有效,但您不会以这种方式使用它.但是你的示例测试无论如何都会失败,因为模拟的函数returnStringFooIfBar不会返回任何东西.

这是它应该如何工作:

$obs = $this->getMock('observer') ;
$obs->expect($this->once()) 
    ->method('returnStringFooIfBar') 
    ->with($this->equlTo('bar'))
    ->will($this->returnValue('foo'));

$returnString= $obs->returnStringFooIfBar ('bar') ;
$this->assertEqual('foo', $returnString) ;
Run Code Online (Sandbox Code Playgroud)

但真实世界的测试案​​例会涉及一些测试对象:

class TestObject {

    private $observer;
    public function __construct($observer) {
        $this->observer = $observer;
    }

    public function doMagicAndNotify() {
        // do heavy magic

        //notify observer
        $obsresult = $this->observer->returnStringFooIfBar('bar');

        return 'didmagic';
    }
}

class TestObjectTest extends PHPUnit_Framework_TestCase {

    public function testObserverCalling() {
        $obs = $this->getMock('observer') ;
        $obs->expect($this->once()) 
            ->method('returnStringFooIfBar') 
            ->with($this->equlTo('bar'));

        $test = new TestObject($obs);
        $returnString= $test->doMagicAndNotify() ;

        $this->assertEqual('didmagic', $returnString) ;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我想要的是一个正常工作的观察者,但确保使用正确的参数调用方法.

据我所知,除了没有运行构造函数/自动加载之外,没有更改原始类的功能.

实际上是另一种方式.Observer的临时子类将覆盖所有(或指定的)方法并更改原始功能(不会执行模拟方法的父级).它不会覆盖构造函数,无论如何都会调用它.

无法断言模拟方法的方法调用并在同一个sime中调用其原始方法.

请参阅方法模板生成器以供参考.

请记住:你没有在这里测试观察者的正确行为,你正在嘲笑它的行为以测试这个主题.

sitenote:$this->returnCallback($someCallback)是一个强大的功能,可能会帮助你.我不喜欢这个想法,但你可以这样做:

public function testObserverCalling() {
    $obs = new Observer();
    $obsmock = $this->getMock('observer') ;
    $obsmock->expect($this->once()) 
        ->method('returnStringFooIfBar') 
        ->with($this->equlTo('bar'))
        ->will($this->returnCallback(array($obs, 'returnStringFooIfBar')));

    $test = new TestObject($obsmock);
    $returnString= $test->doMagicAndNotify() ;

    $this->assertEqual('didmagic', $returnString) ;
}
Run Code Online (Sandbox Code Playgroud)