I'm new to unit testing and PHPUnit, but I've reading a lot lately about design patterns and isolated tests and I've decided to refactor an application I'm working on to get rid of static classes, singletons, hardcoded dependencies and anything else defined on the global scope, hopefully making it "testable" and not a pain in the ass to mantain in the future, since it is meant to be a long term project.
So far I believe I understand the theory behind unit testing, but I was wondering, in a scenario where one delegates handling nested dependencies of objects to a Factory, how should one go about unit testing said Factory, or is it just redundant to test it? And what is the best approach to test that the "chain" of dependencies work well in sync?
Let me illustrate the questions. Suppose you have the following "legacy" code:
class House {
protected $material;
protected $door;
protected $knob;
public function __construct() {
$this->door = new Door();
$this->knob = $this->door->getKnob();
$this->material = "stone";
echo "House material: ".$this->material . PHP_EOL . "<br/>";
echo "Door material: ".$this->door->getMaterial() . PHP_EOL . "<br/>";
echo "Knob material: ".$this->knob->getMaterial() . PHP_EOL . "<br/>";
}
}
class Door {
protected $material;
protected $knob;
public function __construct() {
$this->knob = new Knob();
$this->material = "wood";
}
public function getKnob() {
return $this->knob;
}
public function getMaterial () {
return $this->material;
}
}
class Knob {
protected $material;
public function __construct() {
$this->material = "metal";
}
public function getMaterial () {
return $this->material;
}
}
$house = new House();
This is (as far as my understanding goes) bad for unit testing, so we replace the hardcoded dependencies with DI + a Factory class:
class House {
protected $material;
protected $door;
protected $knob;
public function __construct($door) {
$this->door = $door;
$this->knob = $this->door->getKnob();
$this->material = "stone";
echo "House material: ".$this->material . PHP_EOL . "<br/>";
echo "Door material: ".$this->door->getMaterial() . PHP_EOL . "<br/>";
echo "Knob material: ".$this->knob->getMaterial() . PHP_EOL . "<br/>";
}
}
class Door {
protected $material;
protected $knob;
public function __construct($knob) {
$this->knob = $knob;
$this->material = "wood";
}
public function getKnob() {
return $this->knob;
}
public function getMaterial () {
return $this->material;
}
}
class Knob {
protected $material;
public function __construct() {
$this->material = "metal";
}
public function getMaterial () {
return $this->material;
}
}
class HouseFactory {
public function create() {
$knob = new Knob();
$door = new Door($knob);
$house = new House($door);
return $house;
}
}
$houseFactory = new HouseFactory();
$house = $houseFactory->create();
Now (and again, as far as I understand) House, Door and Knob can be unit tested with mocked dependencies just fine. But:
1) What happens with HouseFactory now?
Should one just:
Not test it since it doesn't have any application logic worth testing yet and Factories generally stay that way. Assume that if the independ tests for House, Door & Knob pass the Factory should be fine.
Refactor the factory somehow, ie, using functions within the class to get each instance in such a way that one may override these functions via PHPUnit to return mock objects, just in case there is some extra logic in the class that could use some testing in the future.
2) Is it feasible to set up tests that rely on several (not mocked) dependencies at once? I understand this is technically not unit testing (integration testing perhaps?) but I guess it's still perfectly doable using PHPUnit? Given the example above, I would like to be able to set up a test that not only tests House, Door, Knob and HouseFactory in isolation, but also the results of the interaction of the real objects with each other, perhaps with some of their functions mocked, such as the ones which deal with data. Is PHPUnit a bad choice for this kind of tests?
Thanks in advance for your time. I realize some of the assumptions I'm making may not be correct, since I'm obviously not an expert on the matter; corrections are welcome and appreciated.
The factory is just like the new keyword. Do you test the new keyword? No, you test if you can construct a class. But that's independent to the factory itself and part of the unit so already part of your unit tests.
2) is called integration testing. And you can do that with PHPUnit as well.
Edit - As there was some discussion in comments:
As far as Unit testing is concerned, you could unit-test your factory that it does for what it is for: return a concrete type, a type or any type at all.
There is nothing wrong with that, however it's normally not necessary as constructors of the returned type(s) are already under unit-tests and well that test is really trivial and just data-checking which smells like integration testing. Also those types which have that type from the factory as dependency (and which are under unit-test as well) will make compilation/execution fail if the dependency can not be provided. So everything the factory is for, is already tested, even from both sides. And if the factory does not get consumed, well then you don't need to test it.
I suggest you create once a factory purely TDD style, so to pre-formulate the use and then you'll get a feeling for this. You might want to test other aspects of your factory class(es), but probably this belongs more into integration than unit testing.
And I don't wanted to create the impression that other of your units should actually have hardcoded calls to the factory create method(s) instead of getting the dependency injected. As you should not use new inside your units, you should not use Factory::create therein either. Similar to new, the class-name (Factory) is hard-encoded, not injected. It is a hidden dependency then. But dependencies should not be hidden; but made visible.
You can test it with inheritance.
Just extend House with a FakeHouse for testing, and then check $material, $door and $knob etc. whether they've changed or not after testing.
Related
I want to implement next fragment of diagram, using PHP.
See composition example diagram below:
We can implement composition in Java using inner classes.
But there is no analog of "inner class" in PHP.
Of course, there are traits. But we can use it in more than one class.
I've implemented composition like this:
class Head {
private static $instance = NULL;
private function __construct(){}
public static function getInstance() {
$traces = debug_backtrace();
if (strcmp($traces[1]['class'], 'Human')) {
echo "<br>Only human has head"; // Exception can be thrown here
return NULL;
}
if (!static::$instance) static::$instance = new self();
return static::$instance;
}
public function __toString() {
return 'Head';
}
}
class Human {
private $head;
public function __construct() {
$this->head = Head::getInstance();
}
public function __toString() {
return 'I have ' . $this->head;
}
}
class Plant {
private $head;
public function __construct() {
$this->head = Head::getInstance();
}
}
$human = new Human();
echo $human;
$superman = new Plant();
Is it right to do so?
Is there better way to implement composition relationship in PHP?
It looks like you are really confused about what "composition" is in OOP.
Composition is an association between two classes, where , for an instance of first class to be instantiated, it is mandatory to provide it with second class. In you particular diagram for Human to exists, it requires a Head. In code it would be:
class Head {
}
class Human {
private $head;
public function __construct(Head $head) {
$this->head = $head;
}
}
$bob = new Human(new Head);
And that's it. No debug_backtrace() and no singleton anti-pattern required. And, btw, this would look almost exactly the same in Java too, even with the option to have inner classes.
As for your posted code. This would be wrong:
if (strcmp($traces[1]['class'], 'Human')) {
echo "<br>Only human has head"; // Exception can be thrown here
return NULL;
}
The diagram did not say that only humans have a head. Only that human must have a head to be instantiated. You can also have $skipper = new Dog(new Head);, which would be perfectly fine.
Composition over inheritance.
Basically composition is a stronger form of aggregation. We could say that relationship between body and head is composition because we can not live without head but relationship between body and a hand is aggregation because we could lose our hand but we can stay alive. There are also weaker relations like direct association and temporary association.
Dependency injection however is just a pattern in which we create those associations (by injecting one class in to another).
In most cases you could recognized composition relationship by constructor which inject another object and assign it to its property and life cycle of object ends and start in the same moment.
Other than that from technical point of view there is not much difference between implementation of each association. It is mostly matter of relation definition rather than implementation.
Composition relation is often used to overwrite/change or enhance injected object class behavior. Don't get too excited or worried about composition. In most cases, the advantages versus inheritance are small, and are most enjoyed by third-party library creators, who use composition to add extra flexibility to their libraries.
Inheriting from parent class and overloading/adding methods gives us similar functionality, but with composition we get more flexibility. For example if our constructor accept object that inherit from Head interface we can use HumanHead class if it extends Head interface but we could also use our class to enhance other creatures which extends from same interface like DogHead or DuckHead...
This is perhaps not the best example but it shows the basic concept.
Be sure to check this [Aggregation vs Composition vs Association vs Direct Association] and this [Association-Aggregation-Composition-Dependency].
I am confused whether to use static method or just simple method.
Lets me give an example, I am using Zend framework 1 project.
I have class like
class Example1
{
public static function getVariable() {
return is_numeric(Zend_Registry::get('config')->Variable) ? Zend_Registry::get('config')->Variable : 0;
}
public function calculateSome($param1, $param2) {
$response = array();
if($param2 == 0) {
$response = number_format(($param1 * self::getvariable()) /100);
} else {
$response = $param1;
}
return $response;
}
}
Usage :
Currently i'm getting variable value like Example1::getVariable() in whole project.
And Calculating like first instantiating a class $class1 = new Example1(); and then calling the function like $class1->calculateSome(1, 0);
I am confused whether it is good to change calculateSome() to public static and call like this Example1::calculateSome(1, 0) or left as it is.
I Have found link when to use static =>
When to use static vs instantiated classes
But I can't understand what it says.
You can find the long answer here: How Not To Kill Your Testability Using Statics
The TL;DR version of it is:
A static method is nothing more than a namespaced function, Foo::bar() does not significantly differ from foo_bar().
Whenever you call a static method, or a function for that matter, you're hardcoding a dependency. The code that reads $bar = Foo::bar(); has a hardcoded dependency to a specific Foo class. It is not possible to change what Foo refers to without changing that part of the source code.
An object is a "soft" dependency. $bar = $foo->bar(); is flexible, it allows room to change what $foo refers to. You use this with dependency injection to decouple code from other code:
function baz(Foo $foo) {
$bar = $foo->bar();
...
}
You can call Foo::bar() anytime from anywhere. If Foo::bar has some dependency it depends on, it becomes hard to guarantee that this dependency is available at the time you're calling the method. Requiring object instantiation requires the object's constructor to run, which can enforce requirements to be set up which the rest of the methods of the object can depend on.
Constructors together with dependency injecting objects into other functions are very powerful to
create seams in your codebase to make it possible to "take it apart" and put it together in flexible ways
put checks into strategic places to ensure requirements are met for certain parts of the code (at object instantiation time the constructor enforces a sane state of its little part of the world, its object), which makes it a lot easier to localise and contain failures.
Think of it like compartmentalising your app and putting firewalls between each compartment with a supervisor in charge of each one; instead of everyone just running around in the same room.
Any time you write new Class, you may as well write Class::staticMethod(), the hardcoded dependency is the same.
So the decision comes down to:
What are the requirements of this class? Does it need to ensure certain preconditions are met before any of its code can run (e.g. a database connection needs to be available), or are all methods just self-contained little helper methods?
How likely are you to maybe want to substitute this class for another class? Does this class produce side effects (e.g. writing to a file, modifying some global state) which may not always be desirable and hence a different version of it may be useful under some circumstances?
May you need more than one instance of this class at the same time, or is the nature of the class such that there are no individual instances needed?
Start using unit tests, which require you to take your app apart and test each little part individually to ensure it works, and you'll see where the advantage of object instantiation and dependency injection lie.
When the method involve instance-based properties/changes u should keep it non-static.
If its a method that is needed for the whole type then use static.
For example u can keep tracks of created instances by this snippet:
class Product {
static $count;
private $name;
public function __construct($name) {
$this->name = $name;
self::$count++;
}
public function getName() {
return $this->name;
}
public static function getCount() {
return self:$count;
}
}
$productA = new Product('A');
$productB = new Product('B');
echo $productA->getName(). ' and ' . $productB->getName(). '<br />'. PHP_EOL;
echo 'Total made products :' . Product::getCount();
Why is testing singletons or registry pattern hard in a language like PHP which is request driven?
You can write and run tests aside from the actual program execution, so that you are free to affect the global state of the program and run some tear downs and initialization per each test function to get it to the same state for each test.
Am I missing something?
While it's true that "you can write and run tests aside of the actual program execution so that you are free to affect the global state of the program and run some tear downs and initialization per each test function to get it to the same state for each test.", it is tedious to do so. You want to test the TestSubject in isolation and not spend time recreating a working environment.
Example
class MyTestSubject
{
protected $registry;
public function __construct()
{
$this->registry = Registry::getInstance();
}
public function foo($id)
{
return $this->doSomethingWithResults(
$registry->get('MyActiveRecord')->findById($id)
);
}
}
To get this working you have to have the concrete Registry. It's hardcoded, and it's a Singleton. The latter means to prevent any side-effects from a previous test. It has to be reset for each test you will run on MyTestSubject. You could add a Registry::reset() method and call that in setup(), but adding a method just for being able to test seems ugly. Let's assume you need this method anyway, so you end up with
public function setup()
{
Registry::reset();
$this->testSubject = new MyTestSubject;
}
Now you still don't have the 'MyActiveRecord' object it is supposed to return in foo. Because you like Registry, your MyActiveRecord actually looks like this
class MyActiveRecord
{
protected $db;
public function __construct()
{
$registry = Registry::getInstance();
$this->db = $registry->get('db');
}
public function findById($id) { … }
}
There is another call to Registry in the constructor of MyActiveRecord. You test has to make sure it contains something, otherwise the test will fail. Of course, our database class is a Singleton as well and needs to be reset between tests. Doh!
public function setup()
{
Registry::reset();
Db::reset();
Registry::set('db', Db::getInstance('host', 'user', 'pass', 'db'));
Registry::set('MyActiveRecord', new MyActiveRecord);
$this->testSubject = new MyTestSubject;
}
So with those finally set up, you can do your test
public function testFooDoesSomethingToQueryResults()
{
$this->assertSame('expectedResult', $this->testSubject->findById(1));
}
and realize you have yet another dependency: your physical test database wasn't setup yet. While you were setting up the test database and filled it with data, your boss came along and told you that you are going SOA now and all these database calls have to be replaced with Web service calls.
There is a new class MyWebService for that, and you have to make MyActiveRecord use that instead. Great, just what you needed. Now you have to change all the tests that use the database. Dammit, you think. All that crap just to make sure that doSomethingWithResults works as expected? MyTestSubject doesn't really care where the data comes from.
Introducing mocks
The good news is, you can indeed replace all the dependencies by stubbing or mock them. A test double will pretend to be the real thing.
$mock = $this->getMock('MyWebservice');
$mock->expects($this->once())
->method('findById')
->with($this->equalTo(1))
->will($this->returnValue('Expected Unprocessed Data'));
This will create a double for a Web service that expects to be called once during the test with the first argument to method findById being 1. It will return predefined data.
After you put that in a method in your TestCase, your setup becomes
public function setup()
{
Registry::reset();
Registry::set('MyWebservice', $this->getWebserviceMock());
$this->testSubject = new MyTestSubject;
}
Great. You no longer have to bother about setting up a real environment now. Well, except for the Registry. How about mocking that too. But how to do that. It's hardcoded so there is no way to replace at test runtime. Crap!
But wait a second, didn't we just say MyTestClass doesn't care where the data comes from? Yes, it just cares that it can call the findById method. You hopefully think now: why is the Registry in there at all? And right you are. Let's change the whole thing to
class MyTestSubject
{
protected $finder;
public function __construct(Finder $finder)
{
$this->finder = $finder;
}
public function foo($id)
{
return $this->doSomethingWithResults(
$this->finder->findById($id)
);
}
}
Byebye Registry. We are now injecting the dependency MyWebSe… err… Finder?! Yeah. We just care about the method findById, so we are using an interface now
interface Finder
{
public function findById($id);
}
Don't forget to change the mock accordingly
$mock = $this->getMock('Finder');
$mock->expects($this->once())
->method('findById')
->with($this->equalTo(1))
->will($this->returnValue('Expected Unprocessed Data'));
and setup() becomes
public function setup()
{
$this->testSubject = new MyTestSubject($this->getFinderMock());
}
Voila! Nice and easy and. We can concentrate on testing MyTestClass now.
While you were doing that, your boss called again and said he wants you to switch back to a database because SOA is really just a buzzword used by overpriced consultants to make you feel enterprisey. This time you don't worry though, because you don't have to change your tests again. They no longer depend on the environment.
Of course, you still you have to make sure that both MyWebservice and MyActiveRecord implement the Finder interface for your actual code, but since we assumed them to already have these methods, it's just a matter of slapping implements Finder on the class.
And that's it. Hope that helped.
Additional Resources:
You can find additional information about other drawbacks when testing Singletons and dealing with global state in
Testing Code That Uses Singletons
This should be of most interest, because it is by the author of PHPUnit and explains the difficulties with actual examples in PHPUnit.
Also of interest are:
TotT: Using Dependency Injection to Avoid Singletons
Singletons are Pathological Liars
Flaw: Brittle Global State & Singletons
Singletons (in all OOP languages, not just PHP) make a particular kind of debugging called unit testing difficult for the same reason that global variables do. They introduce global state into a program, meaning that you can't test any modules of your software that depend on the singleton in isolation. Unit testing should include only the code under test (and its superclasses).
Singletons are essentially global state, and while having global state can make sense in certain circumstances, it should be avoided unless it's necessary.
When finishing a PHP test, you can flush singleton instance like this:
protected function tearDown()
{
$reflection = new ReflectionClass('MySingleton');
$property = $reflection->getProperty("_instance");
$property->setAccessible(true);
$property->setValue(null);
}
I've been reading here a few questions regarding the use of unit testing to test private methods and properties. I'm new to unit testing and would like input on the method I'm trying so that my testing can access private/protected properties and methods.
In the test I was working on I wanted to confirm that passing a particular parameter to the object resulted in a property being set. I'm using SimpleTest for my unit testing education and my test method is as follows:
function test__Construction_Should_Properly_Set_Tables() {
$cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
$tables = $cv->tables;
$this->assertEqual( $tables, $this->standardTableDef );
}
Then I wrote a __get method in CVObject as follows:
function __get( $name ) {
$trace = debug_backtrace();
$caller = $trace[1];
$inTesting = preg_match( '/simpletest/', $caller['file'] );
if ( $inTesting ) {
return $this->$name;
} else {
trigger_error( 'Cannot access protected property CVObject::$' .
$name . ' in ' . $trace[0]['file'] . ' on line ' .
$trace[0]['line'],
E_USER_NOTICE );
}
}
My idea in this is that if the calling file is from SimpleTest, go ahead and make the property available for the testing purposes, but if not, trigger the error. This allows me to keep the property private but be able to use it in testing, which is going to be more important to me with a particular private method I'm about to begin writing.
So, my question is, am I missing something really bad here and should avoid this technique?
If you find yourself stuck and simply must access a private/protected property to enable thorough testing, at least place the code that enables access in your test or testing framework. Embedding testing-only code in production code a) complicates the design, b) adds more code that must be tested, and c) means the code runs differently in production.
You can use Ken's subclass method for protected properties, but if you need to access private and are on PHP 5.3.2+ you can use reflection.
function test__Construction_Should_Properly_Set_Tables() {
$cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
$tables = self::getPrivate($cv, 'tables');
$this->assertEqual( $tables, $this->standardTableDef );
}
static function getPrivate($object, $property) {
$reflector = new ReflectionProperty(get_class($object), $property);
$reflector->setAccessible(true);
return $reflector->getValue($object);
}
Note that getPrivate() won't work as written for properties inherited from superclasses, but it's not too hard to loop up the hierarchy to find the declaring class.
While testing a component, you have to test only it's interface (input, output, exceptions), without considering or even knowing it's internal implementation (even better if one programmer writes test cases and the other does the implementation, please refer to XP and TDD techniques). So, the only thing you have to test are public methods.
To ensure, that your private (helper) methods are written correctly, simply use code coverage analyzer (please checkout Code Coverage tools for PHP) and cover as much code as possible with your test cases.
Your solution will guarantee you a maintenance nightmare. Test cases and component implementation should not be coupled in any way, because coupling would need to be bulletproof or otherwise you'll have to test it too.
A quick and dirty solution is to use protected (instead of private) methods, and then test using a wrapper that makes the methods under test public.
class Foo
{
protected function bar(){} // should really be private but protected will do
}
class FooTestWrapper extends Foo
{
public function bar{} { return parent::bar(); } // this is testable
}
But as ljank points out, testing private methods/implementation can become a maintenance nightmare - it probably means you are doing work that should be farmed out to other classes.
Generally speaking, your code should not contain features just for testing. And while it is debatable if testing private/protected methods is good practice, I find that sometimes and want to test a certain private/protected method in isolation.
Using Netsilik/BaseTestCase (MIT License) you can set/get private variable and call private or protected functions:
composer require netsilik/base-test-case
Class to test:
<?php
namespace App;
class Foo
{
private $bar;
protected function setBar(string $bar)
{
$this->bar = $bar;
}
}
Unit test:
class MyTestCase extends \Netsilik\Testing\BaseTestCase
{
public function test_whenProtectedMethodCalled_thenPrivateMemberSet()
{
$foo = new Foo();
self::callInaccessibleMethod($foo, 'setBar', 'abc');
self::assertEquals('abc', self::getInaccessibleProperty($foo, 'bar'));
}
}
Hope this helps.
I'm trying to get my head round Unit Testing and there's one more piece of the jigsaw I need to find.
What I'm trying to do is write tests for the following code. In this case, I've got a really simple Front Controller (written in PHP).
class frontController
{
public function routeRequest($oRequest)
{
$sClassname = $oRequest->getController();
$sMethod = $oRequest->getAction();
$oController = new $sClassname();
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
}
The problem I have is because the code creates new objects. I can easily mock the request object so that I can tightly control what it will actually do within my test case. I'm not sure the best way to actually replace the controller with a test double.
This article from IBM suggests having a factory method for creating my controller and then overriding this with a specific class used for testing:
class frontController
{
public function routeRequest($oRequest)
{
$sMethod = $oRequest->getAction();
$oController = $this->createController($oRequest);
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
protected function createController($oRequest)
{
$sClassname = $oRequest->getController();
return new $sClassname();
}
}
and then for testing perhaps something like this:
class testFrontController extends frontController
{
public function setMockController($oMockController)
{
$this->oMc = $oMockController;
}
protected function createController($oRequest)
{
return $this->oMockController;
}
}
(note this isn't quite what the article says, but I'm thinking it would be most useful to me if it did this)
Another solution could be to have another class that creates the controller. This would then be a dependent class of the frontController. This way I can replace the factory/creation class during testing with a test double. Something like this:
class frontController
{
public function routeRequest($oRequest, $oControllerFactory)
{
$sMethod = $oRequest->getAction();
$oController = $oControllerFactory->create($oRequest);
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
}
class controllerFactory
{
public function create($oRequest)
{
$sClassname = $oRequest->getController();
return new $sClassname();
}
}
I guess the dependency injection could be taken care of in the front controller constructor or via a setter instead of a parameter to the actual "route" method.
I think I prefer option 2.
Is either of these two methods the right way of going about testing this kind of thing?
(perhaps "good way" would be better word here!)
Any thoughts or suggestions on option 1 vs option 2 appreciated or indeed any alternatives. Remember - the key thing is about how to test an object that itself creates other objects as part of its execution.
Thanks!
You might find this article handy.
It discusses how object creation should be separated from the actual running of the application.
I generally find factories to be a good thing to use for this scenario. In addition to the swappability aspect, it means that additional parameters, data, or dependencies required by the object being created can be stored by the factory, and so the object which actually requests the new object doesn't have to know anything about them...
You do not want to use the real controller but a mock, right ?
It seems to me the simplest way to achieve this would be to subclass the request so that it returns the name of a MockController.
I assume you have thought through your assertions so as to define the goal of what exactly you are testing. Keep in mind that unit tests are going to be testing the returns from your methods, which, in this case, is $oResponse (whatever this may be). As a result, your test assertions will be based on this return value. Since I don't know what that return value is from your code snippets, I can only demonstrate an example that you can complete.
I would recommend PHPUnit for your testing as it seems to be the most complete package for PHP imho (many are fans of SimpleTest, as well ... to each their own).
It would look something like this (Please note that I have left out includes for brevity. Read the PHPUnit documentation for more information):
class AimTest extends PHPUnit_Framework_TestCase{
private $_controller = null;
private $_request = null;
public function setUp(){
$this->_controller = new frontController();
//what does this object's type?
$this->_request = new requestObject();
}
public function testObjectCreation(){
/*
* note, that this is only one of several assertions that could
* be made depending on the return value
*/
$return = $this->_controller->routeRequest($this->_request);
//tailor to what you expect your output to be
$this->assertTrue($return == "my expected output");
}
Hope I didn't miss the mark completely on your stated purpose. Moral of the story is that you can only test what your methods return. If you want to test object instantiation from a method, use the instanceof PHP function against a method that returns that object after instantiation.