DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Testing Patterns: Literal Value

Practical PHP Testing Patterns: Literal Value

Giorgio Sironi user avatar by
Giorgio Sironi
·
May. 30, 11 · Interview
Like (0)
Save
Tweet
Share
861 Views

Join the DZone community and get the full member experience.

Join For Free

Values are present everywhere in tests: the difference between production code and test code is that the first tends to become more general with time, while the second tends to get full of examples.
Managing values for assertions and fixtures creation is one of the task required in creating a test suite. There are multiple patterns that address this concern - today we will see the simplest one, Literal Value.

Implementation

Literal Values are constants that we put in place of input and expected data in tests. Usually these values are of primitive type, such as strings and integers, but the pattern extends to cover simple objects created inline.

The greatest advantage of Literal Values is that they never change: your test suite will run always with the same input data, and occasional test failure will be reproducible simply by re-running the red test. Having to repeat runs for 10 times to be statistically sure that there you have introduced no bug is a measure of last resort, while Literal Values keep the test as much deterministic as possible.

Semantics

Unfortunately Literal Values may lead to obscure tests:

$this->assertEquals(40, $order->calculateTax(100, 20, 3));

In this case making the value a bit more explicit may help:

$this->assertEquals(100 - 20 * 3, $order->calculateTax(100, 20, 3));

When I first saw this approach, I though we were introducing duplication between production code and tests. But actually with this assertion we're testing that the method automates the computation over any possible input, which is a larger step than producing a Literal Value like we do in the test. More complex generation procedures are out of the scope of this pattern.

One thing we have also to pay attention to is the usage of identical values where they are not necessary: if you write the same number in a test in two places, you communicate the intent that those two variables must always be equal. If the SUT is meant to run also with different values, you should definitely use always different values.

Reuse of values is instead beneficial throughout different Test Methods: the reader will know (hopefully) that they are isolated from each other, and a value cannot exit the last } of the method.

Variations

  • Symbolic Constant: we need to use the same value in two places, and communicate this intent. By using directly a literal we should have no misunderstandings, but we may have maintenance issues if we want to replace it and we forgot to check all places. In this case, extracting a constant or even just a member variable on $this centralizes the actual value; it also lets you give it a name (self::MY_VEHICLE instead of 1.)
  • Self-Describing Value: we use values which are only passed around, and do not influence the computation, to convey information about their role. For example, we may call vehicles which we want to delete Old banger and vehicles that must be preserved New flaming Ferrari. We may call a bad driver John Disaster and the good one Mark Rallyist. Dont' get too clever on this, although it is a great place for Easter eggs. Just avoid meaningless names like driver A, B, C and D when you're in a domain-level test where you could choose better.

Example

The code sample shows a group of assertions using Literal Values and how to avoid replicating them too much in different tests.

<?php
class LiteralValueTest extends PHPUnit_Framework_TestCase
{
    const POSITIVE = 1;
    const NEGATIVE = -1;

    public function setUp()
    {
        $this->sut = new SUT();
    }

    /**
     * The most basic of the tests.
     */
    public function testALiteralValueIsUsedForExpectationAndInput()
    {
        $this->assertEquals(5, $this->sut->sum(2, 3));
    }

    /**
     * If we change the result from 1 and -1 to "+1" or to an object,
     * we will have a way to quickly change this test. It's normal refactoring.
     */
    public function testASymbolicConstantIsExtractedToAvoidDuplicatingAValue()
    {
        $this->assertEquals(self::POSITIVE, $this->sut->sign(0));
        $this->assertEquals(self::POSITIVE, $this->sut->sign(1));
        $this->assertEquals(self::POSITIVE, $this->sut->sign(2));
        $this->assertEquals(self::POSITIVE, $this->sut->sign(10));
        $this->assertEquals(self::NEGATIVE, $this->sut->sign(-1));
        $this->assertEquals(self::NEGATIVE, $this->sut->sign(-2));
        $this->assertEquals(self::NEGATIVE, $this->sut->sign(-10));
    }
    
    /**
     * Describing cars that have to be deleted as old and rusty is simpler
     * for the mind RAM of the reader that using A, B and C. Choosing 
     * Self-Describing Values is an art that I have only started exploring.
     */
    public function testASelfDescribingValueIsUsedToMakeTheTestMoreReadable()
    {
        $this->sut->addVehicle('Old rusty car', 1980);
        $this->sut->addVehicle('Bus', 2000);
        $this->sut->addVehicle('Ferrari', 2010);
        $this->sut->deleteVehiclesUpTo(1990);
        // another Literal Value
        $this->assertEquals(2, $this->sut->getVehiclesCount());
    }
}

/**
 * Since we only want to describe the test code in this sample,
 * we use this catch-all SUT which accepts any call.
 */
class SUT
{
    public function __call($method, $arguments) {}
}
Literal (computer programming) PHP Testing

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Building a Real-Time App With Spring Boot, Cassandra, Pulsar, React, and Hilla
  • gRPC on the Client Side
  • Container Security: Don't Let Your Guard Down
  • Spring Boot, Quarkus, or Micronaut?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: