PHPUnit: Doing assertions on non-public variables - php

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?

You can also use Assert::assertAttributeEquals('value', 'propertyName', $object).
See https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L490

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

I just want to point out one thing. Let's forget about private fields for a moment and focus on what client of your class cares about. Your class exposes a contract, in this case - ability to alter and retrieve name (via getter and setter). Expected functionality is simple:
when I set name with setName to "Gerald", I expect to get "Gerald" when I call getName
That's all. Client won't (well, shouldn't!) care about internal implementation. Whether you used private field name, hashset or called web service via dynamically generated code - doesn't matter for client. The bug you are currently experiencing, from user point of view - is not a bug at all.
Whether PHPUnit allows you to test private variables - I don't know. But from unit-testing perspective, you shouldn't do that.
Edit (in response to comment):
I understand your concerns about possible exposure of internal state, however I don't think unit testing is the right tool to deal with that. You can come up with a lot of possible scenarios how something might do something else which wasn't planned. Unit tests are by no means cure for all and shouldn't be used as such.

I agree with the others that in general you want to avoid accessing privates in your tests, but for the cases where you need to, you can use reflection to read and write the property.

Related

How to unit test a method which does not return anything with phpunit [duplicate]

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?
You can also use Assert::assertAttributeEquals('value', 'propertyName', $object).
See https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L490
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
I just want to point out one thing. Let's forget about private fields for a moment and focus on what client of your class cares about. Your class exposes a contract, in this case - ability to alter and retrieve name (via getter and setter). Expected functionality is simple:
when I set name with setName to "Gerald", I expect to get "Gerald" when I call getName
That's all. Client won't (well, shouldn't!) care about internal implementation. Whether you used private field name, hashset or called web service via dynamically generated code - doesn't matter for client. The bug you are currently experiencing, from user point of view - is not a bug at all.
Whether PHPUnit allows you to test private variables - I don't know. But from unit-testing perspective, you shouldn't do that.
Edit (in response to comment):
I understand your concerns about possible exposure of internal state, however I don't think unit testing is the right tool to deal with that. You can come up with a lot of possible scenarios how something might do something else which wasn't planned. Unit tests are by no means cure for all and shouldn't be used as such.
I agree with the others that in general you want to avoid accessing privates in your tests, but for the cases where you need to, you can use reflection to read and write the property.

PHPUnit testing constructorless class

I'm developing unit tests on a project and I came across a class that does not contain constructor.
You may ask yourself, "How does this object exist then?"
Well, in another system, this object is generated and saved in database, so in the system where unit tests are required, there is no constructor defined for that class. But there is a need to test their functions so that if they are modified in the system in the future, the tests will indicate in which situations they are used, this will ensure me not to neglect the other points of the project that use it.
Within this environment, how can you test this type of class?
I tried using mocks, but mock brings all null attributes. In addition, a mocked object only comes as a result of a function that you say previously it will bring. So to test the functions of the object itself, this is not functional.
Any idea?
PS: Sorry for the bad english.
Constructors are optional. A class does not need a constructor for you to be able to instantiate it or test whether its methods are functioning correctly.
As I understand it, you want to test a method which behaves differently depending on a particular property, which would normally be set by a constructor but in your class isn't. That means that in the actual code usage, that property is probably being set directly at some point or there's a different method that sets its value.
In general, for testing these kinds of methods you should always set such a property yourself anyway. The reason for this is simple: a single test should only test one particular method. If you rely on the constructor, your test would be testing the combination of both the constructor and that method. Your test of the method will become dependent on the constructor behaving properly.
Imagine the following:
class Mood {
public $happy;
function __construct() {
$this->happy = true;
}
public function greet() {
if ($this->happy) {
return 'Hi!';
} else {
return 'Go away';
}
}
}
Let's say you want to test the behavior of the greet() method:
class MoodTest extends \PHPUnit\Framework\TestCase {
public function testGreet() {
$mood = new Mood();
$this->assertEqual('Hi!', $mood->greet())
}
}
This test would pass, because we assume the constructor is doing its job and is setting the $happy property to true. But there are two problems here:
We are not testing that the method works properly if $happy is false
We rely on the constructor to set $happy's initial value to true
This means things can change outside our control that would break this specific test, even though the function still works as expected. Business logic may change so that the constructor will set $happy to false initially. Or the developer's logic may change where the constructor disappears entirely and $happy is set in some other way (maybe a setHappy() method is introduced at some point).
To properly test the greet() method, there should be a test for every possible outcome. In this case the method has a single if statement, so there ought to be a test case for both outcomes of that condition:
class MoodTest extends \PHPUnit\Framework\TestCase {
public function testGreetIfHappy() {
$mood = new Mood();
$mood->happy = true;
$this->assertEqual('Hi!', $mood->greet())
}
public function testGreetIfNotHappy() {
$mood = new Mood();
$mood->happy = false;
$this->assertEqual('Go away', $mood->greet())
}
}
Now, no matter what happens to the constructor or business logic, these tests are testing only the behavior of the greet() method. Whatever else the constructor is doing (even if doesn't exist or does nothing at all) no longer has any effect on the tests of the greet() method.

Why is it possible to access private variables from outside class by reference?

If I have a public class method that is returning a reference to a non-visible (private or protected) property, I can use that reference to gain direct access:
PHP code
class A
{
private $property = 'orange';
public function &ExposeProperty()
{
return $this->property;
}
public function Output()
{
echo $this->property;
}
}
$obj = new A();
# prints 'orange'
$obj->Output();
$var = &$obj->ExposeProperty();
$var = 'apple';
# prints 'apple'
$obj->Output();
Is there a reasoning behind this functionality in PHP? Or is it just a design oversight, failing to keep track of access violations through references?
It obviously comes in handy when you want to achieve something like:
PHP code
$this->load->resource();
Where load is an object that modifies given properties of $this. But apart from this shortcut, I don't see many possible uses which wouldn't be possible with valid OOP patterns otherwise.
Well, you are explicitly returning a reference to a value. You're locking the front door, but are then opening a side entrance. You are very deliberately taking aim and shooting your own foot here. If $property was an object, and you'd return this object with or without & reference, any modifications to this object would be reflected on $property as well. That's how a reference works, it always modifies the one and only existing value that the reference points to.
Visibility modifiers aren't magic iron clad "protections". There are any number of ways how you can circumvent a private visibility to access and modify the property. They're mostly there as a flag to yourself and other developers that this property should not be accessed directly, it's for internal use and not a publicly sanctioned API. And PHP will slap you on the wrist should you forget that. Nothing more, nothing less.
Also, nothing is really being violated here. Outside code is at no point accessing or modifying $obj->property. That's the only thing private is supposed to prohibit. You're essentially exposing a public API on your object which modifies a private property. Usually this is done with getter and setter functions, but a by-reference API obviously works as well.

Behavior of $this on inherited methods

I always thought I understood how OOP works (and I have been using it for years), but sometimes I realize some concepts are still not so clear to me.
I just came across this question about method visibility in PHP. The accepted answer explains that a private method cannot be overridden by a child class in PHP. Okay, that makes sense. However, the example made me think about the internal inheritance mechanism in PHP, and the way $this behaves on inherited methods.
Consider this code (example from the PHP Manual, also included in the question mentioned above):
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test();
/*
Output:
Bar::testPrivate
Foo::testPublic
*/
Now consider this excerpt from the PHP Manual:
The pseudo-variable $this is available when a method is called from within an object context. $this is a reference to the calling object (usually the object to which the method belongs, but possibly another object, if the method is called statically from the context of a secondary object).
The explanation states that "$this is a reference to the calling object", which is $myFoo. So I expected that $myFoo->test() would always invoke Foo::testPrivate, and never Bar::testPrivate (unless $myFoo were an instance of Bar). I tested $this with get_class, and it always returns Foo, even from inside Bar::testPrivate and Bar::test. However, $this behaves like an instance of Bar when Bar::test calls $this->testPrivate().
That's really confusing, and I am trying to understand why it works that way!
I thought inherited methods (public or protected) were somehow copied from the base to the child class. Private methods would not be copied at all. But this example indicates that it doesn't work like this. It looks like the instance of Foo keeps an internal instance of Bar, and delegates method calls to it when necessary.
I am trying to learn something here, and I only learn when things make sense to me. This one does not. After writing all this, I think I can summarize it with two questions:
Could someone briefly explain how inheritance works internally in PHP? Or at least point me to an article or documentation about that?
Is the behavior or $this discussed here present on other OO languages as well, or is it particular to PHP?
Inheritance in PHP works the same way it does in most object-oriented languages.
When you have a "virtual" method, the method is not bound directly to the caller. Instead, every class contains a little lookup table which says "this method name is bound to that implementation". So, when you say $this->testPublic(), what actually happens is that PHP:
Gets the virtual table for the current class
Looks up the virtual table entry for testPublic in that table
Invokes the method to which that lookup points
Since Foo overrides testPublic, its virtual table contains an entry for testPublic pointing to Foo::testPublic.
Now, with the private methods, the behavior is different. Since, as you correctly read, private methods cannot be overridden, calling a private method never results in a virtual table lookup. That is to say, private methods cannot be virtual and must always be defined in the class which uses them.
So, the effect is that the name is bound at the time of declaration: all Foo methods will call Foo::testPrivate when they say $this->testPrivate, and all Bar methods will call Bar::testPrivate.
To sum up, saying that "inherited methods are copied to the child" is not correct. What actually happens is that the child begins with its method-name-lookup-table being populated with its parent class' entries, and then adds its own functions and replaces any overridden entries. When you call $this->something, this lookup table is consulted for the current object's class. So if $this is an instance of Foo, and Foo overrides testPublic, you get Foo::testPublic. If $this is an instance of Bar, you will get Bar::testPublic.
Well, private methods and properties are exactly that - private. For all intents and purposes, you can consider them "internal", meaning internal to the class they're defined in. This means that they're never inherited, and can never be overridden.
Thus, when using $this in combination with a private method or property, it will always be the method or property within the same class as the reference to $this. This happens because $this called within a parent class cannot access private methods or properties in another class (because they're private), even from child classes.
Hope this helps.

Is it reasonable to have a fair amount of public properties in a class?

Or in more specific words, is it "ok" to not be relying on setters and getters?
I'm dealing with a class that checks the availability of rooms and sets public properties of which there are more than a dozen. Things such as:
unitNumber
roomTypes ( array )
codeCorporate
codeGroup
numberKids
numberAdults
numberRooms
currency
minRate
maxRate
soapServer
units ( array )
hotelId
And after an object is instantiated those properties are set with $this-> inside various methods. However the code that deals with the object often sets public properties directly instead of using getter/setter methods:
$object->something = 3;
foreach ($object->things as $thing ) { }
If I have the time to refactor this class..
Should I stick all of these properties in a data array that's a private property, and define __set and __get methods?
Should I make a single getter method for each of the properties?
In my opinion, it is rarely a good idea to have any public members. It increases coupling between classes, and makes refactoring very complicated (should you need it.)
Setters/Getters are the way to go, and the very small performance penalty that you pay for it is usually either optimized away, or trumped by elegance.
To answer your question about array vs. single-getter-per-var, it's a matter of taste. I tend to only keep variables of a similar type within an array, and separate the rest.
I personally have yet to find a truly good reason for a public property, though im open for suggestion :-)
Although i much prefer specified getters/setters for each property (whether that's a proxy to a generalized get($name) or not). I assume you have other code already that uses direct assignment so in that case i would say to proceed with using the magic __get/__set methods.
I think most people will recommend using setters & getters. Right now you're limited to simply setting & fetching the property, but what if you want to log when that property is accessed? Or perhaps you want to run the value by a validation function first (email, phonenumber, zip code, etc). Maybe you'll need to call another function, or set another property. I think you see where I'm heading with this. By using setters & getters, you add a valuable layer of encapsulation to your classes, and 99% of the time this is worth the extra typing you'll need to do ;) Imagine trying to do the examples above without setters & getters. It'd be a big headache to say the least.
Edit: I forgot to mention Doctrine. It's an object relation mapper (ORM) that can automatically setup setters & getters for you (amongst other things). You can check it out at http://www.doctrine-project.org/
I would take a step back and ask some more general questions:
Why am I having to expose this much information; what is using it and why?
Is this class really just a data structure without behavior, in which case should be a private class to some other class?
Does this class serve a single purpose, or is it on the path to becoming monolithic?
You may discover that you are able to create views of an instance of a class to export to a database, display in a form, etc. Check out the "Builder" and "Acyclic Visitor" patterns to start with.
Regarding accessors, I do not see a need to use them for what you are describing: retrieving class properties and internal state information, aka a struct. However, for attributes of a class I could see the benefit in certain cases, but more for retrieving attributes, not for mutations of your object's state.
If I may add my grain of salt several months later :
It is very un-OO to have public properties. Everything should be encapsulated, simply because (among other reasons) using direct attribute manipulation doesn't give you ways to easily refactor or perform (more) control checks when some external source modifies the field. For example, let's say you have a class with many fields that is used throughout a project several times, and that project contains several thousands of files; it's a project that has been running and expanded for a few years now. Let's say that the company is changing it's business model, or that a problem is found with some of the field's data type and now is required to have some validation; will you duplicate that validation in all those thousands of source code that is directly accessing the public member? In PHP, the solution may be simple, but not in most OO programming language (i.g. Java). The fact is that OO is based on encapsulation. In short, encapsulation doesn't only produce clean code, but also highly maintainable (not to say cost-effective and cohesive) code.
Your suggestion of having a private member (array) being manipulated by __get / __set is good. This way, if you need some extra validation along the road, simply create your setter and/or your getter and it will be the end of it. Some may argue with that being counter productive as the code completion cannot kick-in on __get / __set. IMHO, relying on code completion is simply lazy coding. But then again, having every member have it's own getter and/or setter allows you to write a more comprehensive API documentation. Personally, I usually use that technique for internal or very general purpose classes. If all your fields do not require any validation, or there are as you said several dozen of them, then using magic methods would be acceptable, in my opinion.
The bottom line is to avoid direct member access on class instances, period. How you decide to achieve this is strictly up to you. Just make sure that the API is well documented the more abstract you make it.
On a final note, in PHP, if you already have classes that are being used that are not encapsulating their fields, for example something like
class SomeObject {
public $foo;
public $bar;
public $baz;
//...
}
you can simply fix this class without having to refactor anything with something like :
class SomeObject {
private $_foo; // having underscore as prefix helps to know what's private/protected
private $_bar; // inside the code.
private $_baz;
public function __get($name) {
$methodName = 'get'.ucfirst($name);
if (method_exists($this, $methodName)) {
return $this->{$methodName}();
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function __set($name, $value) {
$methodName = 'set'.ucfirst($name);
if (method_exists($this, $methodName)) {
$this->{$methodName}($value);
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function getFoo() { return $this->_foo; }
public function setFoo($value) { $this->_foo = $value; }
public function getBar() { return $this->_bar; }
public function setBar($value) { $this->_bar = $value; }
public function getBaz() { return $this->_baz; }
public function setBaz($value) { $this->_baz = $value; }
}
And then
$obj = new SomeObject();
$obj->foo = 'Hello world'; // legacy code support
$obj->setFoo('Hello world'); // same thing, but preferred
And you satisfy both the OO paradigm and having direct access to attributes of an instance. You could also have __call() check for prefix 'get' or 'set' and call __get() and __set() accordingly, but I would not go that far, though this would truly enable general purpose classes to access it's private members via ->member and ->getMember()/->setMember()

Categories