Simple task

I am writing some test cases and I have a test case that uses Mock objects. I need to check if two methods of a class are called from another method of the class. Here's what I did:

First I created a Mock:

Mock::generate('Parser');

      

Then, inside my test, I called:

$P = new MockParser();

$P->expectOnce('loadUrl', array('http://url'));
$P->expectOnce('parse');

$P->fetchAndParse('http://url');

      

My implementation code looks like this:

public function fetchAndParse($url) {
    $this->loadUrl($url);
    $this->parse();
}

      

And the loadUrl and parse () methods definitely exist. I get two failures in my tests, both tell me "The expected call count for [loadUrl] was [1] got [0]". I have no idea what's going on - the methods are called from within this function!

Thanks,

Jamie

+1


a source to share


2 answers


While my experience has been with the mocking frameworks in the .NET world, I think what you are trying to do is wrong.

Any mocking framework, when asked to mock up a class, generates stubs for ALL methods in that class. This includes the fetchAndParse method. Therefore, when you call fetchAndParse on your mock $ P object, the loadUrl and parse methods are NOT called. What you are actually doing is calling the "stubbed" fetchAndParse method.



I'm not very good at PHP, so I don't want to try to fix your test. Hope someone can do this.

+4


a source


You misunderstood how derisive works. If you are using dependency injection to set a helper object in your class, then you can mock your injected object. Then you can simulate the behavior (interface) of the original object. The best way is to mimic interfaces, because you can develop without creating any class that implements the current interface.

In your example:



interface UrlLoaderInterface {

    public function load($url);
}

class YourParser {

    protected $urlLoader;
    protected $source;

    public function setUrlLoader(UrlLoaderInterface $urlLoader) {
        $this->urlLoader = $urlLoader;
    }

    public function fetchAndParse($url) {
        $this->loadUrl($url);
        $this->parse();
    }

    public function loadUrl($url) {
        $this->source = $this->urlLoader->load($url);
    }

    public function parse() {

    }

}

Mock::generate('UrlLoaderInterface', 'MockUrlLoader');

class TestYourParser extends UnitTestCase {

    public function testShouldCallUrlLoaderByFetchAndParse() {
        $testUrl = 'http://url';

        $urlLoader = new MockUrlLoader();
        $urlLoader->expectOnce('load', array($testUrl));
        $urlLoader->returns('load', 'source', array($testUrl));

        $parser = new YourParser();
        $parser->setUrlLoader($urlLoader);
        $parser->fetchAndParse($testUrl);
    }

}

      

Btw. your example is failing because method names cannot contain words like "and", "or", "if", etc. The method allows only one thing to be done. If you use these words, you can be sure that you have poorly designed code.

+1


a source







All Articles