Test doubles
Tien Vo Xuan
Drupal Developer
Go1
What's in this topic
- What is test doubles?
- 5 kinds of test doubles by examples
- How to recognize them?
Test double
or Mock
or Stunt Double (in movies)
Just one thing
When we are writing a test in which we cannot (or chose not to) use a real
depended-on component (DOC), we can replace it with a Test Double. The
Test Double doesn't have to behave exactly like the real DOC; it merely
has to provide the same API as the real one so that the system-under-test (SUT) thinks it is
the real one!
Gerard Meszaros
application
Kinds of double
- Dummy
- Fake
- Stubs
- Spies
- Mocks
Kinds of double
Dummy
objects are passed around but never actually used. Usually they are just used to fill parameter lists.
Dummy
class
CarController {
function
getReadyToGo(EngineInterface
$engine
, GearboxInterface
$gearbox, ElectronicsInterface $electronic
s,
LightsInterface
$light
s) {
$engine
->start();
$gearbox
->shift(
'N'
);
$electronics
->turnOn(
$lights
);
return
true;
}
}
Dummy
$light = $this->getMock('LightInterface');
Dummy
- It does not matter how many times a method is called
- It return null
fake
- It does not matter how many times a method is called
- It does not return null
Fake
$statusPanel = $this->getMock('StatusPanel')
->expects($this->any())
->method('getCurrentSpeed')
->will($this->returnCallback(
function() use ($distance, $time) {
return $distance / $time;
}
));
Stub
stub
function
goForward(Electronics
$electronics
, StatusPanel
$statusPanel
= null) {
$statusPanel
=
$statusPanel
? :
new
StatusPanel();
if
(
$statusPanel
->engineIsRunning() &&
$statusPanel
->thereIsEnoughFuel())
$electronics
->accelerate();
}
stub
$stubStatusPanel
=
$this
->getMock(
'StatusPanel'
)
->expects(
$this
->any()) ->method(
'thereIsEnoughFuel'
) ->will(
$this
->returnValue(TRUE));
$stubStatusPanel->expects($this->any()) ->method('engineIsRunning')
->will($this
->returnValue(TRUE));
Stub
- It does not matter which arguments are provided when one of its methods is called.
- It does not matter how many times a method is called.
- It return a fixed value.
spy
- Keep track of method being called.
- To later examine.
Spy
$currentDirection = null;
$carSpy = $this->getMock('CarController');
$carSpy->expects($this->any())
->method('turnLeft')
->will($this->returnCallback(
function() use(&$currentDirection) {
$currentDirection = 'left';
}
));
// turn right ...
Spy
$remote = new Remote($carSpy);
$remote->turnRight();
$remote->turnLeft();
// ...
$this->assertEquals('right', $currentDirection);
mock
- Just like Spy
- Also: Make sure that the methods were called the expected number of times, in a particular order, with the correct arguments.
mock
$carMock = $this->getMock('CarController');
$carMock->expects($this->at(0))
->method('turnLeft')
->with(30);
$carMock->expects($this->at(1))
->method('turnLeft')
->with(20);
$carMock->expects($this->at(0))
->method('turnRight')
->with(15);
Mock
$remote = new Remote($carMock);
$remote->turnLeft(30);
$remote->turnLeft(20);
$remote->turnRight(15);
mock
The mock is not so interested in the return values of functions. It's more interested in what function were called, with what arguments, when, and how often.
Recognize
- Dummy: neither expects() or method() or with() or will()
- Stub: expects($this->any()) and will($this->returnValue('static value'))
- Fake: expects($this->any()) and will($this->returnCallBack('a callback'));
- Spy: expects($this->any()) and will($this->returnCallBack('use and assign value to global variables'));
- Mock: expects(either at or once or exactly or atLeastOnce or never) and with('arguments') and without will()
references
Q&A
Test double
By Tiến Võ Xuân
Test double
- 1,142