Mocking is a great aid when testing behavior. Like with many other tools, we are abusing them.
Problems
Complexity
False sense of security.
Parallel/Duplicated objects (Real and Mocks)
Maintainability
Solutions
Mock just non-business entities.
Remove mock if its interface has too much behavior.
Sample Code
Wrong
<? | |
class PaymentTest extends TestCase | |
{ | |
public function testProcessPaymentReturnsTrueOnSuccessfulPayment() | |
{ | |
$paymentDetails = array( | |
'amount' => 123.99, | |
'card_num' => '4111-1111-1111-1111', | |
'exp_date' => '03/2013', | |
); | |
$payment = $this->getMockBuilder('Payment') | |
->setConstructorArgs(array()) | |
->getMock(); | |
// You should not mock a business object! | |
$authorizeNet = new AuthorizeNetAIM( | |
$payment::API_ID, $payment::TRANS_KEY); | |
// This is an external and coupled system. | |
// You have no control over it so tests become fragile | |
$paymentProcessResult = $payment->processPayment( | |
$authorizeNet, $paymentDetails); | |
$this->assertTrue($paymentProcessResult); | |
} | |
} |
Right
<?php | |
namespace phpUnitTutorial\Test; | |
use phpUnitTutorial\Payment; | |
class PaymentTest extends \PHPUnit_Framework_TestCase | |
{ | |
public function | |
testProcessPaymentReturnsTrueOnSuccessfulPayment() | |
{ | |
$paymentDetails = array( | |
'amount' => 123.99, | |
'card_num' => '4111-1111-1111-1111', | |
'exp_date' => '03/2013', | |
); | |
$payment = new Payment(); | |
// Payment is a real one | |
$response = new \stdClass(); | |
$response->approved = true; | |
$response->transaction_id = 123; | |
$authorizeNet = $this->getMockBuilder('\AuthorizeNetAIM') | |
->setConstructorArgs( | |
array($payment::API_ID, $payment::TRANS_KEY)) | |
->getMock(); | |
// External system is mocked | |
$authorizeNet->expects($this->once()) | |
->method('authorizeAndCapture') | |
->will($this->returnValue($response)); | |
$result = $payment->processPayment( | |
$authorizeNet, $paymentDetails); | |
$this->assertTrue($result); | |
} | |
} |
Detection
This is an architectural pattern. It will not be easy to create an automatic detection rule.
Exceptions
- Mocking accidental problems (serialization, databases, APIs) is a very good practice to avoid coupling.
Tags
- Abuser
Conclusion
Mocks, like many other test doubles are excellent tools. Choosing wisely when to use them is an art.
Imagine a play in which each actor, instead of rehearsing with other actors, had to interact with 25 scriptwriters. The actors would never rehearse together. How would the result of the play be?
Also Known as
- Faker
More info
Credits
Photo by Syed Ahmad on Unsplash
The pesticide paradox. Every method you use to prevent or find bugs leaves a residue of subtler bugs against which those methods are ineffective.
Boris Beizer
Top comments (0)