Private function error with PHPUnit testing - php

I am getting the following error in my PHPunit test
Warning: Invalid callback Vc_Manager::__sleep, cannot access private method Vc_Manager::__sleep()
This is caused because the function __sleep() is private and the __contruct() function for the class is also private.
How can I using this function in my phpunit testing without turning the function public?
Full code:
require_once('../splitTestNew.php');
class SplitTestTest extends PHPUnit_Framework_TestCase
{
public function setUp(){
}
public function tearDown(){ }
/**
* #runInSeparateProcess
*/
public function testDefaultParameterValues()
{
$obj = new BSSplitTest();
$this->assertTrue($obj->params['A'] == 50);
$this->assertTrue($obj->params['B'] == 50);
$this->assertTrue($obj->params['SplitCookieA'] == 'ACounter');
$this->assertTrue($obj->params['SplitCookieB'] == 'BCounter');
$this->assertTrue($obj->params['TableA'] == 'counter_a');
$this->assertTrue($obj->params['TableB'] == 'counter_b');
}

If your constructor is private then you can't have
$obj = new BSSplitTest();
That implies your constructor is public, you'll need a static factory constructor.
$obj = BSSplitTest::getInstance(); //or createInstance if not singleton

We NEVER test private methods, it doesn't make any sense. You either need to make the function public or test functions that use the private method.
Also, if the constructor is private too, you first need to make an instance of the class (for instance using Factory pattern) and then invoke a function.

Related

PHPUnit - mock method of class use created instance

I want to mock a method foo in a class but leave method bar as it is:
<?php
class MyClass
{
protected $dep1;
protected $dep2;
protected $dep3;
protected $dep4;
/**
* Test constructor.
* #param $dep1
* #param $dep2
* #param $dep3
* #param $dep4
*/
public function __construct($dep1, $dep2, $dep3, $dep4)
{
$this->dep1 = $dep1;
$this->dep2 = $dep2;
$this->dep3 = $dep3;
$this->dep4 = $dep4;
parent::__construct();
}
public function foo()
{
return "foo";
}
public function bar()
{
return "bar";
}
}
However, MyClass is instantiated via a factory which retrieves the dependencies ($dep1, $dep2, ...) and inject them directly in to the constructor of MyClass.
So I want to use that Factory and instantiate a MyClass-object (otherwise the complex instantiation has to be coded in the test case also).
In short I want to know if there is another solution than:
class TestMyClass extends \PHPUnit\Framework\TestCase {
public function setUp()
{
// complicated way to retrieve $dep1 to $dep4
$mock = $this->getMockBuilder(MyClass::class)->setMethods(['foo'])->setConstructorArgs([$dep1, $dep2, $dep3, $dep4])->getMock();
$mock->expects($this->any())->method('foo')->willReturn(false);
}
}
Is it possible to somehow create proxy to an already created instance of MyClass, which just overrides the foo method? Is there another way (without runkit pecl extension) to mock an method of an existing/instantiated object?
I know PHPUnit has some Proxy-related methods, but I couldn't find any documentation / example of usage of them, so I am not sure if they even could be used to solve my problem.

What is the differece between private and protected in OOP?

I don't understand what is the different between private method and protected method in Object Oriented PHP. After make a method private , I'm able to access it from extends class. Please check the code below -
<?php
class person{
private function namedilam(){
return "likhlam";
}
public function kicu(){
return $this->namedilam();
}
}
class second extends person{
}
$info = new second;
echo $info->kicu();
The difference will become clear when you do it like this:
class Liam {
private getFirstName() {
return "Liam";
}
public function getName() {
return $this->getFirstName();
}
}
class Max extends Liam {
private function getFirstName() {
return "Max";
}
}
class Peter extends Liam {
public function getLiamsName() {
return $this->getFirstName();
}
}
$max = new Max();
echo $max->getName();
// returns "Liam", not "Max" as you might expect
$peter = new Peter();
echo $peter->getLiamsName();
// PHP Fatal error: Uncaught Error: Call to private method Liam::getFirstName() [...]
Max will return "Liam" because the getName() calls getFirstName() in the Liam class, not the one from the class extending it. This means with private methods you can make sure that whenever in your class you call this method exactly this one is used and it will never be overwritten.
To explain it in general terms:
private methods are only accessible inside the class. They can not be overwritten or accessed from outside or even classes extending it.
protected methods are accessible inside the class and in extending classes, but you can't call them from outside like:
$max = new Max();
$max->iAmProtected();
This will neither work with private or protected methods.

Tell phpunit to call public instead of private

My Question is. I have a class i want to test (myClass). In myClass there is a function wich calls a private function thats also in the myClass.
I know i can't test private functions. Is it possible to tell phpunit to call another function instead of the private?
Example
$this->testclass is now the class i want to test
$this->testclass = new \stdClass();
$this->testclass->mock = $this->getMockBuilder('myClass')->getMock();
Outside my testcase i have created a fake class.
$this->mockextended = new \stdClass();
$this->mockextended->mock = new MOCKEXTENDEDCLASSES();
in the $this->mockextended i have a public function.
the function i want to test
public function TestMe(){
$this->somePrivateFunctioniHate(); <==== this is the pain in my ass
}
and the private function
private function somePrivateFunctioniHate(){
//come code
}
What i want to do is. the function TestMe is calling a private function.
Is it possible to tell phpunit to override the private function and call another function thats inside $this->mockextended;
I have tried it like this.
$this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction()
only this gives me a nice error. I did this before and it worked. Called it like this
EDIT
For people who don't understand my question.
I have another function that calls another class. I din't want to have another class in my test so i created a fake Class outside my testcase. Inserted the same functions as the class the function wants to include. Did it like this
$this->testclass->chunks = new \stdClass();
//MOCKchunckTpl is the fake class outside my testcase
$this->testclass->chunks->config = new MOCKchunkTpl();
This works. Whenever a function wants to call $this->testclass->chunks->config->Somefunction(); it will be redirected to my fake class.
BUT when i try to do the same with a function thats calling a private function. Like $this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction() it gives a nice error
Fatal error: Can't use method return value in write context in
Short answer: No, there isn't. There is no way for PHPUnit to manipulate private methods.
Mocks are for faking the behavior of classes, which depend on the class you want to test. If you need to overwrite a private method, there is something wrong in your architecture. Private methods should be tested by simple testing the public methods in which they are used. If you need to test it separately, declare it public.
EDIT: Here is an example how you'd test a simple code using a private method or putting this private method in another class:
1. Private method
class MyClass {
public function myMethod() {
return $this->myPrivateMethod();
}
private function myPrivateMethod() {
return 2;
}
}
And the test class:
class MyClassTest extends \PHPUnit_Framework_TestCase {
public function testMyMethod() {
$myClass = new MyClass();
// don't mind the private method, just test if the public method is working
$this->assertEquals(2, $myClass->myMethod());
}
}
1. Second class
class MyClass {
public $dependentClass;
public function myMethod() {
return $this->dependentClass->dependentMethod();
}
}
And the dependent class:
class DependentClass {
public function dependentMethod() {
return 38943;
}
}
Testing MyClass with the DependentClass:
class MyClassTest extends \PHPUnit_Framework_TestCase {
public function testMyMethod() {
$dependentMock = $this->getMockBuilder("DependentClass")->getMock();
$dependentMock->expects($this->any())
->method("dependentMethod")
->willReturn($this->returnValue(2));
$myClass = new MyClass();
$myClass->dependentClass = $dependentMock;
$this->assertEquals(2, $myClass->myMethod());
}
Although we defined a whole other return in DependentClass, the test will still pass, because we mocked it and are able to define every behavior we'd expect DependentClass to have.
But to cleanly test the project, we need to define another test for DependentClass as well to test, if this class is working. This test should fail if it is not working anymore, not the test for MyClass.

PHPUnit testing singleton

I am trying to write a test for some very old code we have using PHPUnit. I've given the rough structure of it here, I am trying to test the isMember() method of ClassB which it inherits from ClassA. It should just be checking if a constant value exists in the class.
The problem I am having is that it is obviously a protected constructor, so I don't know how to test this as I keep getting protected contruct errors in PHPUnit as obviously the constructor is protected. Please advise how I test this?
abstract class ClassA implements InterfaceA {
private $mValueList;
protected static $instance;
protected function __construct() {
}
protected static function getInstance(ClassA $obj) {
if (is_null($obj->instance)) {
$obj->instance = $obj;
}
return $obj->instance;
}
public function isMember($value) {
return isset($this->mValueList[$value]);
}
....more methods......
}
class ClassB extends ClassA {
public static function getInstance() {
return parent::getInstance(new self());
}
const CON1 = 'string1';
const CON2 = 'string2';
}
You would test it like any other class, you just don't use the constructor in the test.
public function testIsMember() {
$classB = ClassB::getInstance();
$this->assertTrue($classB->isMember('string1'));
$this->assertFalse($classB->isMember('foo'));
}
I am making a guess on the assertions and you could refactor the test to use a data provider. But the general idea is the same. You don't invoke the constructor directly in your tests for a singleton. The getInstance method replaces the call to the constructor.

Best practices to test protected methods with PHPUnit

I found the discussion on Do you test private method informative.
I have decided, that in some classes, I want to have protected methods, but test them.
Some of these methods are static and short. Because most of the public methods make use of them, I will probably be able to safely remove the tests later. But for starting with a TDD approach and avoid debugging, I really want to test them.
I thought of the following:
Method Object as adviced in an answer seems to be overkill for this.
Start with public methods and when code coverage is given by higher level tests, turn them protected and remove the tests.
Inherit a class with a testable interface making protected methods public
Which is best practice? Is there anything else?
It seems, that JUnit automatically changes protected methods to be public, but I did not have a deeper look at it. PHP does not allow this via reflection.
If you're using PHP5 (>= 5.3.2) with PHPUnit, you can test your private and protected methods by using reflection to set them to be public prior to running your tests:
protected static function getMethod($name) {
$class = new ReflectionClass('MyClass');
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
public function testFoo() {
$foo = self::getMethod('foo');
$obj = new MyClass();
$foo->invokeArgs($obj, array(...));
...
}
teastburn has the right approach. Even simpler is to call the method directly and return the answer:
class PHPUnitUtil
{
public static function callMethod($obj, $name, array $args) {
$class = new \ReflectionClass($obj);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method->invokeArgs($obj, $args);
}
}
You can call this simply in your tests by:
$returnVal = PHPUnitUtil::callMethod(
$this->object,
'_nameOfProtectedMethod',
array($arg1, $arg2)
);
You seem to be aware already, but I'll just restate it anyway; It's a bad sign, if you need to test protected methods. The aim of a unit test, is to test the interface of a class, and protected methods are implementation details. That said, there are cases where it makes sense. If you use inheritance, you can see a superclass as providing an interface for the subclass. So here, you would have to test the protected method (But never a private one). The solution to this, is to create a subclass for testing purpose, and use this to expose the methods. Eg.:
class Foo {
protected function stuff() {
// secret stuff, you want to test
}
}
class SubFoo extends Foo {
public function exposedStuff() {
return $this->stuff();
}
}
Note that you can always replace inheritance with composition. When testing code, it's usually a lot easier to deal with code that uses this pattern, so you may want to consider that option.
I'd like to propose a slight variation to getMethod() defined in uckelman's answer.
This version changes getMethod() by removing hard-coded values and simplifying usage a little. I recommend adding it to your PHPUnitUtil class as in the example below or to your PHPUnit_Framework_TestCase-extending class (or, I suppose, globally to your PHPUnitUtil file).
Since MyClass is being instantiated anyways and ReflectionClass can take a string or an object...
class PHPUnitUtil {
/**
* Get a private or protected method for testing/documentation purposes.
* How to use for MyClass->foo():
* $cls = new MyClass();
* $foo = PHPUnitUtil::getPrivateMethod($cls, 'foo');
* $foo->invoke($cls, $...);
* #param object $obj The instantiated instance of your class
* #param string $name The name of your private/protected method
* #return ReflectionMethod The method you asked for
*/
public static function getPrivateMethod($obj, $name) {
$class = new ReflectionClass($obj);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
// ... some other functions
}
I also created an alias function getProtectedMethod() to be explicit what is expected, but that one's up to you.
I think troelskn is close. I would do this instead:
class ClassToTest
{
protected function testThisMethod()
{
// Implement stuff here
}
}
Then, implement something like this:
class TestClassToTest extends ClassToTest
{
public function testThisMethod()
{
return parent::testThisMethod();
}
}
You then run your tests against TestClassToTest.
It should be possible to automatically generate such extension classes by parsing the code. I wouldn't be surprised if PHPUnit already offers such a mechanism (though I haven't checked).
I'm going to throw my hat into the ring here:
I've used the __call hack with mixed degrees of success.
The alternative I came up with was to use the Visitor pattern:
1: generate a stdClass or custom class (to enforce type)
2: prime that with the required method and arguments
3: ensure that your SUT has an acceptVisitor method which will execute the method with the arguments specified in the visiting class
4: inject it into the class you wish to test
5: SUT injects the result of operation into the visitor
6: apply your test conditions to the Visitor's result attribute
You can indeed use __call() in a generic fashion to access protected methods. To be able to test this class
class Example {
protected function getMessage() {
return 'hello';
}
}
you create a subclass in ExampleTest.php:
class ExampleExposed extends Example {
public function __call($method, array $args = array()) {
if (!method_exists($this, $method))
throw new BadMethodCallException("method '$method' does not exist");
return call_user_func_array(array($this, $method), $args);
}
}
Note that the __call() method does not reference the class in any way so you can copy the above for each class with protected methods you want to test and just change the class declaration. You may be able to place this function in a common base class, but I haven't tried it.
Now the test case itself only differs in where you construct the object to be tested, swapping in ExampleExposed for Example.
class ExampleTest extends PHPUnit_Framework_TestCase {
function testGetMessage() {
$fixture = new ExampleExposed();
self::assertEquals('hello', $fixture->getMessage());
}
}
I believe PHP 5.3 allows you to use reflection to change the accessibility of methods directly, but I assume you'd have to do so for each method individually.
I suggest following workaround for "Henrik Paul"'s workaround/idea :)
You know names of private methods of your class. For example they are like _add(), _edit(), _delete() etc.
Hence when you want to test it from aspect of unit-testing, just call private methods by prefixing and/or suffixing some common word (for example _addPhpunit) so that when __call() method is called (since method _addPhpunit() doesn't exist) of owner class, you just put necessary code in __call() method to remove prefixed/suffixed word/s (Phpunit) and then to call that deduced private method from there. This is another good use of magic methods.
Try it out.
Alternative.The code below is provided as an example.
Its implementation can be much broader.
Its implementation that will help you test private methods and replacing a private property .
<?php
class Helper{
public static function sandbox(\Closure $call,$target,?string $slaveClass=null,...$args)
{
$slaveClass=!empty($slaveClass)?$slaveClass:(is_string($target)?$target:get_class($target));
$target=!is_string($target)?$target:null;
$call=$call->bindTo($target,$slaveClass);
return $call(...$args);
}
}
class A{
private $prop='bay';
public function get()
{
return $this->prop;
}
}
class B extends A{}
$b=new B;
$priv_prop=Helper::sandbox(function(...$args){
return $this->prop;
},$b,A::class);
var_dump($priv_prop);// bay
Helper::sandbox(function(...$args){
$this->prop=$args[0];
},$b,A::class,'hello');
var_dump($b->get());// hello
You can use Closure as in the code below
<?php
class A
{
private string $value = 'Kolobol';
private string $otherPrivateValue = 'I\'m very private, like a some kind of password!';
public function setValue(string $value): void
{
$this->value = $value;
}
private function getValue(): string
{
return $this->value . ': ' . $this->getVeryPrivate();
}
private function getVeryPrivate()
{
return $this->otherPrivateValue;
}
}
$getPrivateProperty = function &(string $propName) {
return $this->$propName;
};
$getPrivateMethod = function (string $methodName) {
return Closure::fromCallable([$this, $methodName]);
};
$objA = new A;
$getPrivateProperty = Closure::bind($getPrivateProperty, $objA, $objA);
$getPrivateMethod = Closure::bind($getPrivateMethod, $objA, $objA);
$privateByLink = &$getPrivateProperty('value');
$privateMethod = $getPrivateMethod('getValue');
echo $privateByLink, PHP_EOL; // Kolobok
$objA->setValue('Zmey-Gorynich');
echo $privateByLink, PHP_EOL; // Zmey-Gorynich
$privateByLink = 'Alyonushka';
echo $privateMethod(); // Alyonushka: I'm very private, like a some kind of password!
I made a class for invoking easily private methods (static and non-static) for unit-testing purposes:
class MethodInvoker
{
public function invoke($object, string $methodName, array $args=[]) {
$privateMethod = $this->getMethod(get_class($object), $methodName);
return $privateMethod->invokeArgs($object, $args);
}
private function getMethod(string $className, string $methodName) {
$class = new \ReflectionClass($className);
$method = $class->getMethod($methodName);
$method->setAccessible(true);
return $method;
}
}
Example of usage:
class TestClass {
private function privateMethod(string $txt) {
print_r('invoked privateMethod: ' . $txt);
}
}
(new MethodInvoker)->invoke(new TestClass, 'privateMethod', ['argument_1']);

Categories