0

Writing unit tests for code which is already written is fun sometimes.

I am writing a test case for the following code (an example):

<?php class mockPrivate { public static function one($a){ $var = static::_two($a); return $var; } private static function _two($a){ return $a+1; } } ?> 

The test class is like this:

<?php require_once 'mockPvt.php'; class mockPrivate_test extends PHPUnit_Framework_TestCase { public $classMock; protected function setUp(){ $this->classMock = $this->getMock('mockPrivate', array('_two')); } public function test_one(){ $a = 1; $retVal = 2; $classmock = $this->classMock; $classmock::staticExpects($this->once()) ->method('_two') ->with($a) ->will($this->returnValue($retVal)); $value = $classmock::one($a); $this->assertEquals($value, $retVal); } } ?> 

After running by $ phpunit mockPrivate_test.php I got this error:

PHP Fatal error: Call to private method Mock_mockPrivate_531a1619::_two() from context 'mockPrivate' in /data/www/dev-sumit/tests/example s/mockPvt.php on line 6 

But if I change the

private static function _two() to public static function _two() or protected static function _two() 

it works totally fine. Since this is a legacy code I can't change the private to public/protected. So is there any way I can test the function one or Is this a limitation of phpunit?

2
  • how about is_callable()? I genuinely don't know whether this function is context sensitive or not, it's not documented as far as I can see... Commented Aug 19, 2011 at 22:42
  • 2
    possible duplicate of PhpUnit private method testing Commented Aug 20, 2011 at 12:38

3 Answers 3

2

Another option is to create a class that extends mockPrivate, allowing accessibility to the object you wish to test. Your engineers should be thinking long and hard about why something is private (because that means the class is not easily extensible). Also remember that you can mock the test class if you need to override what it returns.

class Test_MockPrivate extends MockPrivate { /** * Allow public access to normally protected function */ public static function _two($a){ return parent::_two($a); } } // Code to force the return value of a now public function $mock = $this->getMock('Test_MockPrivate', array('_two')); $mock->expects($this->any()) ->method('_two') ->will($this->returnValue('Some Overridden Value'); 
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Mike. I haven't got time to test this but was wondering, can we mock private functions with the new PHPUnit 3.6?
@Sumitk Looks like they cannot mock privates in 3.7 see: phpunit.de/manual/3.7/en/test-doubles.html "Limitations Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior."
Don't forget, protected methods cannot be mocked either.
1

You can use reflection for changing visibility of methods. You can find more info in PHP object, how to reference?

3 Comments

Reflection's setAccessible() will only allow you to call the method from outside the class via the reflection object. It won't change the fact that the method cannot be overridden which is required for mocking.
@David - I think the private cannot be mocked as it cant be overridden in this case. So does everyone who uses phpunit leave that function part uncovered where private functions are called? I did find this link - link where people have modified the framework to support testing private. I will try that. Thanks for your comment!
@Sumitk - You can use setAccessible() to test private methods (though many will say that's not a good idea), but for mocking you are out of luck. You can change it to protected or leave it unmocked when testing methods that call it.
0

Use mock and reflection... (posted this solution, since this is the top google result)

$oMock = $this->getMock("Your_class", array('methodToOverride')); $oMock->expects( $this->any() ) ->method('methodToOverride') ->will( $this->returnValue( true ) ); $oReflection = new ReflectionClass("Your_Class"); $oMethod = $oReflection->getMethod('privateMethodToInvoke'); $oMethod->setAccessible( true ); $oMethod->invoke( $oMock ); 

1 Comment

This isn't what's asked.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.