Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing if a protected method was called

Tags:

phpunit

I´m trying to test if a protected method is called in a public interface.

<?php
abstract class SomeClassAbstract
{ 
    abstract public foo();

    public function doStuff() 
    {    
        $this->_protectedMethod();
    }

    protected function _protectedMethod();
    {
        // implementation is irrelevant
    }
}

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testCalled()
    {
        $mock = $this->getMockForAbstractClass('SomeClass');
        $mock->expects($this->once())
             ->method('_protectedMethod');

        $mock->doStuff();
    }
}

I know it is called correctly, but PHPUnit says its never called.

The same happens when I test the other way, when a method is never called:

<?php
abstract class AnotherClassAbstract
{ 
    abstract public foo();

    public function doAnotherStuff() 
    {    
        $this->_loadCache();
    }

    protected function _loadCache();
    {
        // implementation is irrelevant
    }
}

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testCalled()
    {
        $mock = $this->getMockForAbstractClass('AnotherClass');
        $mock->expects($this->once())
             ->method('_loadCache');

        $mock->doAnotherStuff();
    }
}

The method is called but PHPUnit says that it is not.

What I´m doing wrong?

Edit I wasn´t declaring my methods with double colons, it was just for denoting that it was a public method (interface). Updated to full class/methods declarations.

Edit 2 I should have said that I´m testing some method implementations in an abstract class (edited the code to reflect this). Since I can not instantiate the class, how can I test this?

I´m thinking in creating an SomeClassSimple extending SomeClassAbstract and testing this one instead. Is it the right approach?

like image 499
Luiz Damim Avatar asked Nov 05 '09 13:11

Luiz Damim


People also ask

Can you test a protected method?

So yes, you would test private and protected methods if you felt they needed to be tested for you to answer Yes to the question. The take on (2) Preventing regression of behavior: Once you've got working code, you need to have a mechanism in place to protect this code from future damage.

How do you write test cases for protected methods?

The easiest way would be to make sure your tests are in the same package hierarchy as the class you are testing. If that's not possible then you can subclass the original class and create a public accessor that calls the protected method.

Can we test protected methods in Java?

To test a protected method using junit and mockito, in the test class (the class used to test the method), create a “child class” that extends the protagonist class and merely overrides the protagonist method to make it public so as to give access to the method to the test class, and then write tests against this child ...

How do you access a protected method in unit testing?

A protected member is accessible within its class and by derived class instances. In the unit test you can then use ExposedFooRequirementHandler as the class under test.


1 Answers

In the version of PHPUnit that I have, the class PHPUnit_Framework_MockObject_Mock uses PHP's get_class_methods to determine the interface of the object being mocked. get_class_methods will pick out only the public methods, not the protected or private ones.

This is in keeping with the spirit of xUnit unit testing. Consider the PHPUnit docs' example on how to use Mock Objects. There, the SUT is Subject, which has a protected method notify. The method being tested, though, is doSomething. Considering Subject as a black box, we don't care about the details of how it is implemented. We do care, though, about its behavior. Specifically, we require that when we call doSomething, then the update method of any attached observers is called. So we mock the third party object Observer, and we set up the expectation that its update method will be called. Note that although the protected method notify is exercised, it is not named explicitly in the test. That gives us the freedom to change the implementation any time we like, just so long as the behavior is preserved.

Returning to your example.

class MyTest extends PHPUnit_Framework_TestCase
{
  public function testCalled()
  {
    $mock = $this->getMock('SomeClass');
    $mock->expects($this->once())
         ->method('_protectedMethod');

    $mock->doStuff();
  }
}

Here, your testCalled method creates no instance of the System Under Test (SUT), which would be SomeClass. The version of doStuff in the mock of SomeClass doesn't do anything. In particular, it doesn't call _protectedMethod.

like image 138
Ewan Todd Avatar answered Sep 28 '22 08:09

Ewan Todd