Page 1 of 1
Mocking objects
Posted: Fri Oct 05, 2007 12:12 pm
by Luke
I'm using simpletest and it's going pretty well, but any time that I need to mock something, I've found that it's much easier to simply extend the class I'm mocking and return whatever value I need to return in the subclass. Is this common practice? Seems like the best "actor" would be a subclass... am I wrong? It seems like you need to fake too much with simpletest's mock objects. I'm just looking for discussion on the subject I guess.
Posted: Fri Oct 05, 2007 7:02 pm
by Jenk
That's the easiest way to do it, but in a TDD world, it's not possible - the objects you are mocking may not exist yet.
Interfaces play a big part of it, but yet again, those interfaces may not exist - the tests help you define those interfaces.
Basically, mock objects help design. Your first tests will only satisfy the highest level of requirements, then after refactoring, and thus creating more tests, you'll be separating behaviour into it's own object. Again, going back to TDD, those separated, specific objects will not exist when you write the tests.
Anyway, enough alcohol fuelled babble.. if the objects you are extending and overriding did not exist, would your tests pass? The answer is a quick flat "no" so we mock an object with a specified interface to ensure that the test will pass even without it's dependencies existing. On a sidenote, I personally prefer to use SimpleTest's mock object API to generate predictable results, rather than manually write them. Creating a series of varying results is easy, not so if I had to create those results myself.
The there is always the case of "What if the mock behaviour I have created is causing the failure? Should I test my mock object?" which pops up.
Posted: Fri Oct 05, 2007 7:39 pm
by Luke
OK, that is very interesting. That is the issue I've always run into with TDD. "How in the world do I test objects when their dependancies don't exist". In this particular situation I had actually given up on testing my library until I had at least base classes for my components. I was under the misconception that you needed an existing class for the Mock::Generate() method to work. I now understand it really does just mock an object. Thanks.
Posted: Sat Oct 06, 2007 6:55 am
by Maugrim_The_Reaper
Just reiterating mostly.
Mock Objects serve a few purposes:
- stand in for as yet non-existing classes; or
- force you to determine a public API/interface sooner rather than later by writing a PHP Interface to mock
- add goals for the non-existing object in terms of interaction, return values, etc. (half the work done right there)
- represent an interaction test since Mock Objects are self-validating
- enforce isolation of the Unit under examination from any other Unit/Resource (though this is not strictly a TDD requirement)
This is probably why I only learned PHPUnit recently - it had no Mock Object support up until recently. And I even think the current incarnation lacks a certain flexibility. In short, I find it uncomfortably limiting. For
PHPSpec and PHPT Travis and myself are looking into developing a standalone Mock Object library not bound to one single framework. As soon as Travis gets SimpleTest migrated to subversion at long last probably

. The PHP5 expedition is taking place soon.
The only weakness people tend to see, if viewing from a testing rather than a designing perspective, is that all your tests won't interact with real objects - so this is where you should being in a little Integration Testing or Acceptance Testing (both are almost identical in a small library).
Posted: Sat Oct 06, 2007 7:35 am
by Chris Corbyn
You don't have to use simpletest's generator to create mock objects. You can create your own concrete mock object classes which implement that interface you want to mock. It's tedious without a generator though.
I should add that (and I've only started to fully grasp this recently) if you're feeling like setting up your mocks is too tasking then your interfaces are probably more complex than they need to be.
Posted: Sat Oct 06, 2007 10:31 am
by Jenk
Usually when I create a test case, I'll write up the interface within the same file of the dependencies; be it an interface or just a blank class declaration with the method / property names like so:
Code: Select all
<?php
require('filecontainingtheclassiamtesting.php');
class Dependency {
public function someMethod() {}
public function someOtherMethod() {}
}
Mock::Generate('Dependency');
class MyTestCase extends UnitTestCase {
public function __construct () {
$reflect = new ReflectionClass($this);
$reflect = $reflect->getParentClass()->getConstrutor()->getName();
$this->$reflect();
}
public function testSomethingOrOther () {
$mock = new MockDependency($this);
$mock->expectOnce('someMethod');
$object = new ObjectBeingTested();
$object->setSomething($mock);
//etc..
}
}
?>
Even when the depndency exists, I still prefer to test like the above. This does have a draw back though, I need to remember that if I change the interface of an object which others use, to update the test cases for all of them. To solve this I also use integrated tests and try to implement FIT/Fitnesse as best I can.
Posted: Sat Oct 06, 2007 1:37 pm
by Christopher
I think I am with Jenk here. When I build a Mock Object it is usually either:
1. an interface to a subsystem that I don't want to have to deal with during development (e.g., database)
2. an interface to a class that I am building in parallel with classes dependent on it.
I will write tests for the Mock to verify that it is functioning properly. For #1 I write minimal tests to verify that it works properly. For #2 I write tests just like all the other classes I am developing.