3

I'm new to Unit test and I'm experimenting with PHPUnit framework.

I have a function that calls two others function:

class Dummy{
    public function dummyFunction(){
        $this->anotherDummyFunction();
        .....
        $this->yetAnotherDummyFunction();
    }
    public function anotherDummyFunction(){

        .....

    }
    public function yetAnotherDummyFunction(){

        .....

    }
}

I want test that the two functions be called when I invoke dummyFunction().

Here the test class:

class TestDummyClass {
    public function testDummyFunction(){

        $dummyClassMock = $this->getMockBuilder('Dummy')
                     ->setMethods( array( 'anotherDummyFunction','yetAnotherDummyFunction' ) )
                     ->getMock();

        $dummyClassMock->expects($this->once())
             ->method( 'anotherDummyFunction' );

        $dummyClassMock->expects($this->once())
             ->method( 'yetAnotherDummyFunction' );

        $dummyClassMock->dummyFunction();
   }
}

Now I've notice that if I mock the Dummy class in this way, the result is

Expectation failed for method name is equal to anotherDummyFunction when invoked 1 time(s). Method was expected to be called 1 times, actually called 0 times.

But If I set the Mock Object in this way

$dummyClassMock = $this->getMockBuilder('Dummy')
                     ->setMethods( array( 'anotherDummyFunction' ) )
                     ->getMock();

the test pass. Lastly, if I set the mock object with setMethods(null), the test fails again

It seems that I could pass an array with only one element, the method that I want check if is called. But I've seen here: https://jtreminio.com/2013/03/unit-testing-tutorial-part-5-mock-methods-and-overriding-constructors/ that setMethods is used for inject the return value of the method passed, so this wouldn't have an effect on the call itself, unless I put the dummyFunction in setMethods (In this case the function will return null without call the other two methods, and in this way yes, the test have to fail)

I've made something wrong? I've seen pieces of code where are more than one methods in setMethods()... Why the test fails if I put tho methods in setMethods?

Thanks

2
  • Well, it's strange, but it worked for me. By the way, are you sure that TestDummyClass is inherited from PHPUnit_Framework_TestCase? And what version of phpunit are you using? Mine is 4.6.9. Commented Aug 5, 2015 at 12:46
  • Thank you Alexander, yes, it inherits from PHPUnit_Framework_TestCase, infact other test pass. I'm working with text sublime and the PHPUnit plugin for text sublime. The version of the phpUnit is 4.6.6 but I don't think I can use a new version because of the plugin. Later I will try with another editor with a new version of phpUnit Commented Aug 5, 2015 at 15:42

1 Answer 1

3

You are using $this->once(), which means that the test can only pass if the method is called exactly once – in every test case where the mock is used!

What you probably want is $this->any() which does not require the method to be called every time.

Sign up to request clarification or add additional context in comments.

3 Comments

What do you mean with "the test can only pass if the method is called exactly once – in every test case where the mock is used" ? That, if I have two test methods the function must be call in either or the test wouldn't pass? If I test for $this->any() doesn't the test pass even if the method isn't call at all? (0 calls pass?) I have declared the mock as method variable, so it isn't accessible from other test method
Yes, if you have two test* methods, the mocked method must be called exactly once in each (not more, not less) when using $this->once(). It is true that the test passes if the method isn't called at all. Are you sure that the methods are actually called? If you only call them inside dummyFunction in your production code, they will not be called by the mock dummyFunction.
Why they don't be called by the mock dummyFunction? It is a mock, not a stub... a mock will do what the real method do.. a stub only return null or whatever do you set. So if the real method calls the other two method, the mock will have the same behavior, the methods have to be call and the test have to pass

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.