DEV Community

Cover image for Code Smell 30 - Mocking Business
Maxi Contieri
Maxi Contieri

Posted on • Edited on • Originally published at maximilianocontieri.com

1

Code Smell 30 - Mocking Business

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

  1. Mock just non-business entities.

  2. 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

Mocking is a code smell

Mocks aren't stubs

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

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay