Page 2 of 2
Posted: Sun Oct 21, 2007 5:51 pm
by Weirdan
To avoid any chance of method name collisions, I'd use a "proxy" object which takes the mock object as a constructor parameter, and has nothing else declared except __call(), __set() and __get(). I then pass this object as the dependency/mock. (This is what I use in Smalltalk, paraphrased in PHP)
You mean something like this? :
Code: Select all
$mock = new Mock('ClassName');
$expectation = $mock->expectCall('someMethod');
$expectation->acceptArgs($arrayOfArgs);
$expectation->expectCallCount(2);
class Proxy {
private $_obj;
public function __construct($obj) {
$this->_obj = $obj;
}
public function __call($method, $args) {
return call_user_func_array(array($this->_obj, $method), $args);
}
public function __set($name, $value) {
$this->_obj->$name = $value;
}
public function __get($name) {
return $this->_obj->$name;
}
}
$anotherObj = new AnotherClass(new Proxy($mock));
$anotherObj->doWhatever();
I don't see how this would prevent any name clashes... suppose the ClassName has expectCall method of its own... how would you go about preventing name clashes in that case?
Posted: Sun Oct 21, 2007 7:27 pm
by Jenk
The definition would be more like:
Code: Select all
class MockProxy {
private $_mock;
public function __construct ($mock) {
$this->_mock = $mock;
}
public function __call($method, $args) {
return $this->_mock->returnForCall($method, $args);
}
public function __get($propety) {
return $this->_mock->returnPropety($property);
}
public function __set($property, $val);
$this->_mock->setProperty($property, $val);
}
}
$mock = new MockObject('SomeClass');
$expect = $mock->expectCall('someMethod');
$expect->expectCallCount(1)->with(true, 1)->with(false, 2);
$objectBeingTested = new ClassBeingTested($mock->proxy());
// within test..
$this->assertEqual($objectBeingTest->whatever(), 'foo');
The Proxy handles the interface mocking, whilst the MockObject handles the behaviour mocking, and the expectation handles the expected behaviour of a method or property.
The Proxy also allows for "tidier" testing. The Poxy passes anything and everything passed to it, and the MockObject will store any invalid or unexpected calls until such a time when you validate, so the test doesn't break with unexpected failed calls and allows the test/spect suite to continue.