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.
Related
I'm new to testing and writing testable code, and am looking for some clarification on the correct way to handle this simple scenario. I've read other questions and answers on SO with similar titles but they do not seem to offer a clear answer to what I'm asking.
I have a controller that calls the shipped() method on an instance of my Picking class:
class MyController extends \BaseController {
public function controllerMethod() {
$picking = new Picking;
$picking->shipped($shipmentData);
}
}
The Picking model looks like this:
class Picking extends \Eloquent {
public function order() {
return $this->belongsTo('Order');
}
public function shipped($shipmentData) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$this->order->pickingShipped();
}
}
As you can see, this shipped() method saves some data, and then calls the pickingShipped() method, on it's related Order.
Now, I am trying to write a test for the shipped() method, and I'm not sure the appropriate way to do this. I've read about mocking, but I am confused if this is a situation where mocking is necessary. I've thought of a few possible solutions, but I'm not sure if any of them are correct.
1) Rearrange the code so that the controller calls the pickingShipped() method allowing it to be removed from the shipped() method, simplifying the test.
For example, the last line of the shipped() method would be removed, and the controller code would change to:
$picking = new Picking;
$picking->shipped($shipmentData);
$picking->order->pickingShipped();
2) In the test, use a mock method on order so that the test can simply confirm that the pickingShipped() method gets called.
Something along the lines of what's explained here. That would mean the test could do something like this:
$order->expects($this->once())->method('pickingShipped')
However, I think that would mean that I also need to inject the order dependency rather than relying on the order relationship within the shipped() method, like this:
class Picking extends \Eloquent {
public function order() {
return $this->belongsTo('Order');
}
public function shipped(Order $order, $shipmentData) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$order->pickingShipped();
}
}
And then the code in the controller would have to look like this:
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
This feels a little strange, but I'm really not sure what's right.
My question is, what is the proper way to write and test this code? It's easy to test the the shipped() method sets the appropriate data on itself, but what about that call to pickingShipped() at the end? This seems to make the testing more complicated. So should the code be rearranged? If so, how? Or, is this a common use-case for mocking like I outlined in the 2nd option? If so, is it correct to inject the dependency as I'm showing?
I'm not a PHP dev so this might come down to language features being a blocker.
I would suggest that the dependency injection method is better because it calls out the dependency and would allow you to separate your persistence and behavior later. For instance the Picking or Picker might be a better behavior name whilst PickingRecord might be nice for the data.
In any case if you can set default arguments in PHP then I like the last method you used (injection) and you could currently simplify to something like
public function shipped($shipmentData, Order $order = $this->order) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$order->pickingShipped();
}
This then would allow you to ignore the order dependency in production code and inject a double or other type of object as an order in tests and simply assert that the method was called on the order object. Integration tests should continue to monitor that the interfaces still mesh together even though you're injecting doubles in your unit tests.
This would be how I'd attempt to do this in Ruby.
I came up with a solution that I feel good about. It seems pretty obvious now that I see it. All I did was set the $picking->order property to return the mocked order for the test.
$order = Mockery::mock(Order::class);
$picking = new Picking;
$picking->order = $order;
$order->shouldReceive('pickingShipped')
->with($picking)
->once();
$picking->shipped($shipmentData);
Now when the shipped() method calls $this->order, it gets the mocked $order object I defined, and the test works correctly.
This feels like the right solution.
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();
Given this class:
class MyBuilder {
public function build($param1, $param2) {
// build dependencies ...
return new MyClass($dep1, $dep2, $dep3);
}
}
How can I unit test this class?
Unit-testing it means I want to test its behavior, so I want to test it builds my object with the correct dependencies. However, the new instruction is hardcoded and I can't mock it.
For now, I've added the name of the class as a parameter (so I can provide the class name of a mock class), but it's ugly:
class MyBuilder {
public function build($classname, $param1, $param2) {
// build dependencies ...
return new $classname($dep1, $dep2, $dep3);
}
}
Is there a clean solution or design pattern to make my factories testable?
Factories are inherently testable, you are just trying to get too tight of control over the implementation.
You would check that you get an instance of your class via $this->assertInstanceOf(). Then with the resulting object, you would make sure that properties are set properly. For this you could use any public accessor methods or use $this->assertAttribute* methods that are available in PHPUnit.
http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.assertions.assertEquals
Many of the common assertions also have the ability to check attributes for protected and private properties.
I wouldn't specify the classname in your parameter list, as your usage is that the factory will only return one type and it is only the dependencies that are changed. Making it return a mock object type is unnecessary and makes your test more complicated.
The test would end up looking like this:
public function testBuild() {
$factory = new MyBuilder();
//I would likely put the following into a data provider
$param1 = 'foo';
$param2 = 'bar';
$depen1 = 'boo';
$depen2 = 'baz';
$depen3 = 'boz';
$object = $factory->build($param1, $param2);
$this->assertInstanceOf('MyClass', $object);
//Check the object definition
//This would change depending on your actual implementation of your class
$this->assertAttributeEquals($depen1, 'attr1', $object);
$this->assertAttributeEquals($depen2, 'attr2', $object);
$this->assertAttributeEquals($depen3, 'attr3', $object);
}
You are now making sure that your factory returns a proper object. First by making sure that it is of the proper type. Then by making sure that it was initialized properly.
You are depending upon the existence of MyClass for the test to pass but that is not a bad thing. Your factory is intended to created MyClass objects so if that class is undefined then your test should definitely fail.
Having failing tests while your developing is also not a bad thing.
So what do you want to test?
so I want to test it builds my object with the correct dependencies.
I do see a problem with this. It's either possible that you can create an object with incorrect dependencies (which should not be the case in the first place or tested in other tests, not with the factory) or you want to test a detail of the factory that you should not test at all.
Otherwise - if it's not mocking the factory what you're looking for - I see no reason why a simple
$actual = $subject->build($param1, $param2);
$this->assertInstanceOf('MyClass', $actual);
would not make it. It tests the behavior of the factory build method, that it returns the correct type.
See as well Open-Close-Principle
For tests, you can just create your MockBuilder which extends from your Builder:
class MyMockBuilder extends MyBuilder {
public function build($param1, $param2) {
// build dependencies ...
return new MyMockClass($dep1, $dep2, $dep3);
}
}
Making the classname a parameter 1:1 seems not practical to me, because it turns the factory over into something different. The creating is a detail of the factory, nothing you externalize. So it should be encapsulated. Hence the MockBuilder for tests. You switch the Factory.
As I see it, you ned to verify two things for that builder:
the correct instance is returned
values, that are injected are the right ones.
Checking instance is the easy part. Verifying values needs a bit of trickery.
The simples way to do this would be altering the autoloader. You need to make sure that when MyClass is requested for autoloader to fetch, instead of /src/app/myclass.php file it loads /test/app/myclass.php, which actually contains a "transparent" mock (where you with simple getters can verify the values).
bad idea
Update:
Also, if you do not want to mess with autoloader, you can just at th top of your myBuilderTest.php file include the mock class file, which contains definition for MyClass.
... this actually seems like a cleaner way.
namespace Foo\Bar;
use PHPUnit_Framework_TestCase;
require TEST_ROOT . '/mocks/myclass.php'
class MyBuilderTest extends PHPUnit_Framework_TestCase
{
public function MyBuilder_verify_injected_params_test()
{
$target = new MyBuilder;
$instance = $target->build('a', 'b');
$this->assertEquals('a', $instance->getFirstConstructorParam();
}
}
Lately I have been trying to create my own PHP framework, just to learn from it (As we may look into some bigger and more robust framework for production). One design concept I currently have, is that most core classes mainly work on static functions within classes.
Now a few days ago, I've seen a few articles about "Static methods are death to testability". This concerned me as.. yeah.. my classes contain mostly static methods.. The main reason I was using static methods is that a lot of classes would never need more than one instance, and static methods are easy to approach in the global scope. Now I'm aware that static methods aren't actually the best way to do things, I'm looking for a better alternative.
Imagine the following code to get a config item:
$testcfg = Config::get("test"); // Gets config from "test"
echo $testcfg->foo; // Would output what "foo" contains ofcourse.
/*
* We cache the newly created instance of the "test" config,
* so if we need to use it again anywhere in the application,
* the Config::get() method simply returns that instance.
*/
This is an example of what I currently have. But according to some articles, this is bad.
Now, I could do this the way how, for example, CodeIgniter does this, using:
$testcfg = $this->config->get("test");
echo $testcfg->foo;
Personally, I find this harder to read. That's why I would prefer another way.
So in short, I guess I need a better approach to my classes. I would not want more than one instance to the config class, maintain readability and have easy access to the class. Any ideas?
Note that I'm looking for some best practice or something including a code sample, not some random ideas. Also, if I'm bound to a $this->class->method style pattern, then would I implement this efficiently?
In response to Sébastien Renauld's comments: here's an article on Dependency Injection (DI) and Inversion of Control (IoC) with some examples, and a few extra words on the Hollywood principle (quite important when working on a framework).
Saying your classes won't ever need more than a single instance doesn't mean that statics are a must. Far from it, actually. If you browse this site, and read through PHP questions that deal with the singleton "pattern", you'll soon find out why singletons are a bit of a no-no.
I won't go into the details, but testing and singletons don't mix. Dependency injection is definitely worth a closer look. I'll leave it at that for now.
To answer your question:
Your exaple (Config::get('test')) implies you have a static property in the Config class somewhere. Now if you've done this, as you say, to facilitate access to given data, imagine what a nightmare it would be to debug your code, if that value were to change somewhere... It's a static, so change it once, and it's changed everywhere. Finding out where it was changed might be harder than you anticipated. Even so, that's nothing compared to the issues someone who uses your code will have in the same situation.
And yet, the real problems will only start when that person using your code wants to test whatever it is he/she made: If you want to have access to an instance in a given object, that has been instantiated in some class, there are plenty of ways to do so (especially in a framework):
class Application
{//base class of your framework
private $defaulDB = null;
public $env = null;
public function __construct($env = 'test')
{
$this->env = $env;
}
private function connectDB(PDO $connection = null)
{
if ($connection === null)
{
$connection = new PDO();//you know the deal...
}
$this->defaultDB = $connection;
}
public function getDB(PDO $conn = null)
{//get connection
if ($this->defaultDB === null)
{
$this->connectDB($conn);
}
return $this->defaultDB;
}
public function registerController(MyConstroller $controller)
{//<== magic!
$controller->registerApplication($this);
return $this;
}
}
As you can see, the Application class has a method that passes the Application instance to your controller, or whatever part of your framework you want to grant access to scope of the Application class.
Note that I've declared the defaultDB property as a private property, so I'm using a getter. I can, if I wanted to, pass a connection to that getter. There's a lot more you can do with that connection, of course, but I can't be bothered writing a full framework to show you everything you can do here :).
Basically, all your controllers will extend the MyController class, which could be an abstract class that looks like this:
abstract class MyController
{
private $app = null;
protected $db = null;
public function __construct(Application $app = null)
{
if ($app !== null)
{
return $this->registerApplication($app);
}
}
public function registerApplication(Application $app)
{
$this->app = $app;
return $this;
}
public function getApplication()
{
return $this->app;
}
}
So in your code, you can easily do something along the lines of:
$controller = new MyController($this);//assuming the instance is created in the Application class
$controller = new MyController();
$controller->registerApplication($appInstance);
In both cases, you can get that single DB instance like so:
$controller->getApplication()->getDB();
You can test your framework with easily by passing a different DB connection to the getDB method, if the defaultDB property hasn't been set in this case. With some extra work you can register multiple DB connections at the same time and access those at will, too:
$controller->getApplication->getDB(new PDO());//pass test connection here...
This is, by no means, the full explanation, but I wanted to get this answer in quite quickly before you end up with a huge static (and thus useless) codebase.
In response to comments from OP:
On how I'd tackle the Config class. Honestly, I'd pretty much do the same thing as I'd do with the defaultDB property as shown above. But I'd probably allow for more targeted control on what class gets access to what part of the config:
class Application
{
private $config = null;
public function __construct($env = 'test', $config = null)
{//get default config path or use path passed as argument
$this->config = new Config(parse_ini_file($config));
}
public function registerController(MyController $controller)
{
$controller->setApplication($this);
}
public function registerDB(MyDB $wrapper, $connect = true)
{//assume MyDB is a wrapper class, that gets the connection data from the config
$wrapper->setConfig(new Config($this->config->getSection('DB')));
$this->defaultDB = $wrapper;
return $this;
}
}
class MyController
{
private $app = null;
public function getApplication()
{
return $this->app;
}
public function setApplication(Application $app)
{
$this->app = $app;
return $this;
}
//Optional:
public function getConfig()
{
return $this->app->getConfig();
}
public function getDB()
{
return $this->app->getDB();
}
}
Those last two methods aren't really required, you could just as well write something like:
$controller->getApplication()->getConfig();
Again, this snippet is all a bit messy and incomplete, but it does go to show you that you can "expose" certain properties of one class, by passing a reference to that class to another. Even if the properties are private, you can use getters to access them all the same. You can also use various register-methods to control what it is the registered object is allowed to see, as I've done with the DB-wrapper in my snippet. A DB class shouldn't deal with viewscripts and namespaces, or autoloaders. That's why I'm only registering the DB section of the config.
Basically, a lot of your main components will end up sharing a number of methods. In other words, they'll end up implementing a given interface. For each main component (assuming the classic MVC pattern), you'll have one abstract base-class, and an inheritance chain of 1 or 2 levels of child classes: Abstract Controller > DefaultController > ProjectSpecificController.
At the same time, all of these classes will probably expect another instance to be passed to them when constructed. Just look at the index.php of any ZendFW project:
$application = new Zend_Application(APPLICATION_ENV);
$application->bootstrap()->run();
That's all you can see, but inside the application, all other classes are being instantiated. That's why you can access neigh on everything from anywhere: all classes have been instantiated inside another class along these lines:
public function initController(Request $request)
{
$this->currentController = $request->getController();
$this->currentController = new $this->currentController($this);
return $this->currentController->init($request)
->{$request->getAction().'Action'}();
}
By passing $this to the constructor of a controller class, that class can use various getters and setters to get to whatever it needs... Look at the examples above, it could use getDB, or getConfig and use that data if that's what it needs.
That's how most frameworks I've tinkered or worked with function: The application is kicks into action and determines what needs to be done. That's the Hollywood-principle, or Inversion of Control: the Application is started, and the application determines what classes it needs when. In the link I provided I believe this is compared to a store creating its own customers: the store is built, and decides what it wants to sell. In order to sell it, it will create the clients it wants, and provide them with the means they need to purchase the goods...
And, before I forget: Yes, all this can be done without a single static variable, let alone function, coming into play. I've built my own framework, and I've never felt there was no other way than to "go static". I did use the Factory pattern at first, but ditched it pretty quickly.
IMHO, a good framework is modular: you should be able to use bits of it (like Symfony's components), without issues. Using the Factory pattern makes you assume too much. You assume class X will be available, which isn't a given.
Registering those classes that are available makes for far more portable components. Consider this:
class AssumeFactory
{
private $db = null;
public function getDB(PDO $db = null)
{
if ($db === null)
{
$config = Factory::getConfig();//assumes Config class
$db = new PDO($config->getDBString());
}
$this->db = $db;
return $this->db;
}
}
As opposed to:
class RegisteredApplication
{//assume this is registered to current Application
public function getDB(PDO $fallback = null, $setToApplication = false)
{
if ($this->getApplication()->getDB() === null)
{//defensive
if ($setToApplication === true && $fallback !== null)
{
$this->getApplication()->setDB($fallback);
return $fallback;//this is current connection
}
if ($fallback === null && $this->getApplication()->getConfig() !== null)
{//if DB is not set #app, check config:
$fallback = $this->getApplication()->getConfig()->getSection('DB');
$fallback = new PDO($fallback->connString, $fallback->user, $fallback->pass);
return $fallback;
}
throw new RuntimeException('No DB connection set #app, no fallback');
}
if ($setToApplication === true && $fallback !== null)
{
$this->getApplication()->setDB($fallback);
}
return $this->getApplication()->getDB();
}
}
Though the latter version is slightly more work to write, it's quite clear which of the two is the better bet. The first version just assumes too much, and doesn't allow for safety-nets. It's also quite dictatorial: suppose I've written a test, and I need the results to go to another DB. I therefore need to change the DB connection, for the entire application (user input, errors, stats... they're all likely to be stored in a DB).
For those two reasons alone, the second snippet is the better candidate: I can pass another DB connection, that overwrites the application default, or, if I don't want to do that, I can either use the default connection, or attempt to create the default connection. Store the connection I just made, or not... the choice is entirely mine. If nothing works, I just get a RuntimeException thrown at me, but that's not the point.
Magic methods would help you: see the examples about __get() and __set()
You should also take a look at namespaces: it may help you to get rid of some classes with static methods only.
I have a class that looks something like this:
class Foo {
protected $_arr = array();
public function has($key) {
return array_key_exists($key, $this->_arr);
}
public function add($key, $val) {
$this->_arr[$key] = $val;
}
}
For my PHPUnit tests for these methods, the only way I can think if to test add() is by asserting that has() returns TRUE for the same key after adding it. This makes my testAdd() test dependent on my testHas() test. Conversely, the only way I can think of to test has() is basically doing the exact same steps, but this would make this test dependent on an already dependent test, producing a chicken and egg type problem.
Am I going about this the wrong way? What's a better method for testing stuff like this?
Instead of writing one-test-per-method, design your tests around the functionality the class must provide. You'll have tests that exercise multiple methods, but that's fine because it indicates to the developer that those methods are related. This is where Test Driven Development--where you write the tests while designing the contract for the class before writing the code for the class--really shines.
class FooTest extends PHPUnit_Framework_TestCase
{
function testStartsEmpty() {
$foo = new Foo;
self::assertFalse($foo->has('bar'));
}
function testAddStoresKeys() {
$foo = new Foo;
$foo->add('bar', 'baz');
self::assertTrue($foo->has('bar'));
}
function testAddStoresKeysWithNullValues() {
$foo = new Foo;
$foo->add('bar', null);
self::assertTrue($foo->has('bar'));
}
function testAddStoresValues() {
$foo = new Foo;
$foo->add('bar', 'baz');
self::assertEquals('baz', $foo->get('bar')); // fatal error
}
}
Now that testAddStoresValues() fails, it's time to implement a method to get the value for a given key: Foo::get($key).
PHPUnit allows testing of non-public members.
However, using $sut->has() to find out whether $sut->add() worked is perfectly fine. Also, when you test $sut->add(), you dont need to write a separate test for $sut->has() as well, because it's covered in the $sut->add() test already. Just add a #covers annotation.
In reference to the long dicussions in the comments to #Gordon s answer:
The unit in unit testing is the object not the method! You don't want to test methods in isolation from the other methods of the objects. (If you wanted to do so just use functions ;) ) - It's really important to test how the object behaves and if it does the expected think when called and not how the methods interact internally.
I've recently written a blog post explaining why it is important to not test single methods in isolation:
http://edorian.posterous.com/the-unit-in-unit-testing
Quoting from my post:
Unit testing, in PHP, is about testing the observable behaviors of a class
Most importantly:
Observable from the outside! Nobody cares about the internal state of a class if it never changes the outcome of a method call.
Take this sample:
public function setValue($value) {
$this->value = $value;
}
public function execute() {
if (!$this->value) {
throw new Exception("No Value, no good");
}
return $value * 10; // business logic
}
It sounds trivial but the distinction is important and more easy to overlook when looking at bigger classes.
What do we test there?
IF we don’t setValue AND then call execute an exception is thrown!
IF we DO setValue AND then call execute we get an computed result
So we are testing two behaviors of your class and not the methods in isolation!
IMO you can test behavior of the object. So you can test if has return false before and true after adding some stuff into collection.