Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit: Doing assertions on non-public variables

Suppose I have a class with a private property and associated public getter and setter. I want to test with PHPUnit that the property gets the correct value after the setter has been used or that the getter returns the correct property.

Of course I can test the setter by using the getter to see that the object is storing the correct value, and vice versa for testing the getter. However, this doesn't guarantee that the private property is the one being set.

Say I had the following class. I created a property, getter and setter. But I made a typo in the property name, so the getter and the setter don't actually manipulate the property they're meant to manipulate

class SomeClass {     private          $mane = NULL; // Was supposed to be $name but got fat-fingered!      public function getName ()     {         return ($this -> name);     }      public function setName ($newName)     {         $this -> name = $newName;         return ($this);     } } 

If I run the following test

public function testSetName () {     $this -> object -> setName ('Gerald');     $this -> assertTrue ($this -> object -> getName () == 'Gerald'); } 

I would get a pass. However, something very bad has actually happened that I don't want. When setName() is called, it actually creates a new property in the class with the name I thought my private property had, only the one that the setter creates is public! I can demonstrate that with the following code:

$a  = new SomeClass;  $a -> setName('gerald'); var_dump ($a -> getName ()); var_dump ($a -> name); 

It would output:

string(6) "gerald"

string(6) "gerald"

Is there any way I can access the private properties from PHPUnit so I can write tests that make sure that the properties I think are being get and set actually really are being get and set?

Or is there some other thing I should be doing in a test to catch problems like this without trying to get access to the private state of the object under test?

like image 561
GordonM Avatar asked Jan 19 '12 15:01

GordonM


People also ask

What is assertion in PHPUnit?

The assertEquals() function is a builtin function in PHPUnit and is used to assert whether the actual obtained value is equals to expected value or not. This assertion will return true in the case if the expected value is the same as the actual value else returns false.

Which method is used to create a mock with PHPUnit?

PHPUnit provides methods that are used to automatically create objects that will replace the original object in our test. createMock($type) and getMockBuilder($type) methods are used to create mock object. The createMock method immediately returns a mock object of the specified type.

What are PHPUnit fixtures?

Fixtures of a test involve writing a code to set the world up in a known state, and after the test, return it back to its original state. When testing array operations in PHPUnit, the array stored in the `$stack` variable is simply the fixture.


2 Answers

You can also use Assert::assertAttributeEquals('value', 'propertyName', $object).

See https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L490

like image 78
Gildas Avatar answered Oct 11 '22 07:10

Gildas


For testing properties, I'd make the same arguments I make then talking about testing private methods.

You usually don't want to do this.

It's about testing observable behavior.

If you rename all your properties or decide to store them into an array you should not need to adapt your tests at all. You want your tests to tell you that everything still works! When you need to change the tests to make sure everything still works you lose all the benefits as you also could make an error changing the tests.

So, all in all, you lose the value of you test suite!


Just testing the get/set combinations would be ok enough but usually not every setter should have a getter and just creating them for testing is not a nice thing ether.

Usually, you set some stuff and then tell the method to DO (behavior) something. Testing for that (that the class does what is should do) is the best option for testing and should make testing the properties superfluous.


If you really want to do that there is the setAccessible functionality in PHP reflections API but I can't make up an example where I find this desirable

Finding unused properties to catch bugs / issues like this one:

The PHP Mess Detector As a UnusedPrivateField Rule

class Something {     private static $FOO = 2; // Unused     private $i = 5; // Unused     private $j = 6;     public function addOne()     {         return $this->j++;     } } 

This will generate two warnings for you because the variables are never accessed

like image 24
edorian Avatar answered Oct 11 '22 06:10

edorian