Home Testing The State of PHP Testing in 2018

The State of PHP Testing in 2018

Author

Date

Category

Testing code is an essential aspect of writing software of any level of quality.
Itโ€™s essential because it helps us know the code works as it should; whether it’s a specific unit of functionality or the application as a whole from an end user’s perspective.ย  In this article we will address the status of PHP testing from a variety of perspectives.

From testing languages to people working behind the scenes, I intend to show you itโ€™s an excellent time for testing in PHP right now. Dive in, have a read and share your thoughts in the comments.

Scalar Type-hinting and Return Type Declaration Support

It might seem like a bit of a strange way to start talking about the state of testing, by talking about PHPโ€™sย scalar type-hintingย andย return type declaration support.

However, without this addition I wouldnโ€™t consider the state of testing to be as mature as it now is. If youโ€™re not familiar with scalar type-hinting and return type declarations in PHP, take a look at the following code.

<?php
class Document
{
  public function titlecase(string $text): string
  {
    if (strlen($text) === 0) {
      return;
    }
    return preg_replace_callback(
      self::SEARCH_REGEX,
      function ($match) {
        $tmp = preg_replace_callback(
          sprintf(โ€˜/\b(%s)\b/iโ€™, implode(โ€˜|โ€™, self::SMALL_WORDS)),
          function ($m) {
            return strtolower($m[0]);
          },
          $match[2]
        );
        return sprintf(โ€˜%s[%s]โ€™, $match[1], $tmp);
      },
      $text
    );
  }
}

You can see thereโ€™s a class (‘Document’) with one method (‘titlecase’). The method takes one argument, ‘$text’, which must be a string. The function also returns a string.

Letโ€™s consider what this means for the code and its usage. Itโ€™s clear you have to supply a string and the function returns a string. To be fair, we could have specified any other scalar type or a user-defined class or interface instead.

So at that level, nothing is particularly special about the use of scalar types.
However, when considered in aggregate, itโ€™s a significant improvement. Why?

Because the codeโ€™s intent is more explicit than it was before. It signals its intentions much more concretely. From a validation perspective, the language can now check the types passed to and back from a function, so the need to do so in code is no longer there.

class FilenameToLabelConverterTest extends TestCase
{
  public function converterDataProvider()
  {
    $original = <<<EOD
modules/admin_manual/pages/appliance/ucs/add-groups-and-users.adoc[Add-groups-and-users]
modules/admin_manual/pages/appliance/Active_Directory.adoc[Active Directory]
modules/admin_manual/pages/appliance/Backup.adoc[Backup]
modules/admin_manual/pages/appliance/Collabora.adoc[Collabora]
modules/admin_manual/pages/appliance/clamav.adoc[Clamav]
modules/admin_manual/pages/appliance/howto-update-owncloud.adoc[Howto-update-owncloud]
modules/admin_manual/pages/appliance/index.adoc[Index]
modules/admin_manual/pages/appliance/installation.adoc[Installation]
modules/admin_manual/pages/appliance/managing-ucs.adoc[Managing-ucs]
modules/admin_manual/pages/appliance/what-is-it.adoc[What-is-it]
EOD;

$formatted = <<<EOD
modules/admin_manual/pages/appliance/ucs/add-groups-and-users.adoc[Add groups and users]
modules/admin_manual/pages/appliance/Active_Directory.adoc[Active Directory]
modules/admin_manual/pages/appliance/Backup.adoc[Backup]
modules/admin_manual/pages/appliance/Collabora.adoc[Collabora]
modules/admin_manual/pages/appliance/clamav.adoc[ClamAV]
modules/admin_manual/pages/appliance/howto-update-owncloud.adoc[Howto update ownCloud]
modules/admin_manual/pages/appliance/index.adoc[Index]
modules/admin_manual/pages/appliance/installation.adoc[Installation]
modules/admin_manual/pages/appliance/managing-ucs.adoc[Managing UCS]
modules/admin_manual/pages/appliance/what-is-it.adoc[What is it]
EOD;
    return [
      [
        $original,
        $formatted
      ]
    ];
 }
 /**
  * @dataProvider converterDataProvider
  * @param string $from
  * @param string $to
  */
  public function testCanCorrectlyConvertStringToTitlecase(
    string $from, string $to
  ) {
    $converter = new FilenameToLabelConverter();
    $this->assertSame($to, $converter->titlecase($from));
  }
}

Now letโ€™s validate that assertion. Take the above tests as a jumping off point. You can see they only need to supply string test data.

Thereโ€™s no need to supply data of any other data type, as the language ensures the function cannot accept it. As a result, the tests are shorter and take less time toย write,ย verify, andย maintain. Whatโ€™s more,ย they are easier to read!

Should You Always Useย Types?

Iโ€™m not saying they should always be used. I agree there are times and places for not using them. However, when used appropriately, they reduce the need for testing.

Whatโ€™s more, thereโ€™s less testing and validation required, for checking the return values from function calls. If youโ€™re not sure of what I mean, consider the above example without the use of scalar type-hinting and return type declarations.

In this scenario, the language cannot enforce only strings are supplied to the function. Given that, you would have to add a series of tests to ensure it returned the correct result when it was passed a string, and when it was passed any number of other data types.

  • Which situation is more precise, cleaner, and more maintainable?
  • Which situation results in higher developer satisfaction and less cost?

Taking this, albeit simplistic, example as a reference point, scalar type hinting and return types is the better choice to make. As a result of these features, itโ€™s a lot easier to test in PHP than ever before.

Testing Frameworks

PHP has a large number of testing frameworks and tools available to choose from. Admittedly, of those only a few enjoy a significant level of support.
These includeย Behat,ย Codeception,ย Mockery, andย PHPUnitย (PHPโ€™s de facto testing tool).

Letโ€™s have a quick look at these now, to see what they offer.

Mockery

Mockery
Mockery

Modern testing can be quite an involved task, requiring a wide-variety of techniques and approaches for fully testing code, andย Mockeryย is an excellent tool to help achieve that. If you have not heard of it before, hereโ€™s a short overview, from the projectโ€™s documentation:

Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human-readable Domain Specific Languageย (DSL).

It provides support forย test doubles,ย method stubs,ย method call expectations, andย test spies, along with a host of related functionality.

I admit that, at first, I found it a little confusing. However, after spending some time with it, it is an excellent tool to have in your testing tool belt.

If youโ€™re keen to know more about it, check out the documentation, or Robert Basicโ€™s article โ€œEasier Mocking with Mockeryโ€ in this monthโ€™s edition of PHP[Arch] magazine.

Behat

Behatโ€Šโ€”โ€ŠA PHP framework for autotesting your business expectations.
Behatโ€Šโ€”โ€ŠA PHP framework for autotesting your business expectations.

Quoting Behatโ€™s website:

Behat is an open source Behavior-Driven Development framework for PHP. It is a tool to support you in delivering software that matters through continuous communication, deliberate discovery, and test-automation.

Behatย providesย BDD (Behavior Driven Development)ย testing support, and structures tests in the โ€œContext-Action-Outcomeโ€ orย Gherkin format. It allows a human-readable feature file, such as in the following example, to guide the creation of an almost equally human-readable test suite.

Feature: Product basket
 In order to buy products
 As a customer
 I need to be able to put interesting products into a basket

 Rules:
 โ€” VAT is 20%
 โ€” Delivery for basket under ยฃ10 is ยฃ3
 โ€” Delivery for basket over ยฃ10 is ยฃ2

Like Mockery, when I first started with Behat, I found it a bit confusing; perhaps this was because I was so used to using PHPUnit style of testing.
So to change from one style to another was a bit of a stretch. However, having said this, after getting over that initial hurdle, I have found it an excellent tool.

Codeception

Codeceptionโ€Šโ€”โ€ŠElegant and Efficient Testing for PHP.
Codeceptionโ€Šโ€”โ€ŠElegant and Efficient Testing for PHP.

Whereas Behat focuses exclusively on BDD-style testing,ย Codeceptionย is a comprehensive testing suite. Self-described as โ€œElegant and Efficient Testing for PHPโ€, it:

  • Supports acceptance, functional, and unit tests
  • Supports BDD-style testing
  • Supports web services
  • Supports code coverage, parallel execution, and continuous integration
  • Has modules for integrating withย AngularJS,ย Facebook,ย Laravel 5,ย MongoDB,ย Phalcon,ย Redis,ย RESTย andย SOAP servers,ย Zend Framework versions 1 and 2,ย Zend Expressive,ย Yii,ย Symfonyย Joomla, andย WordPress

In addition to these features, it has excellent command-line tooling support for bootstrapping a majority of this functionality. Iโ€™ve used it on several projects and can personally testify to just how thorough it is, and just how supportive the core development team is.

If youโ€™re looking for an almost one-stop-testing-shop for PHP, then Codeception is the way to go. Whatโ€™s more, the core development team have even recently started providing enterprise-level support.

PHPUnit

PHPUnit
PHPUnit

If youโ€™ve been around PHP for any length of timeโ€Šโ€”โ€Šespecially in recent yearsโ€Šโ€”โ€Šthen youโ€™ll know aboutย PHPUnit. PHPUnit is the granddaddy of testing tools for PHP, arguably the de facto standard.

After a quick glance at the manual shows you it has significant functionality. It shouldn’t come as a surprise it’s used by so many within the PHP community.

Its functionality includes:

  • Test fixtures
  • Database testing
  • Organizing tests
  • Test doubles
  • Logging
  • Code coverage analysis
  • Docblock annotations
  • Data providers
  • A massive number of assertions
  • A feature-rich command-line test running and an XML-based configuration file

In addition to this, it integrates with numerous other tools, such as Mockery.
If youโ€™re on the lookout for the right tool to use to start testing your PHP code, PHPUnit is the place to start.

Static Codeย Analysis

Now that weโ€™ve covered several of the most popular testing tools, letโ€™s turn to static code analysis support. If youโ€™re not familiar with the term,ย static code analysisย is:

The analysis of computer software that is performed without actually executing programs. In most cases, the analysis is performed on some version of the source code, and in the other cases, some form of the objectย code.

By using them, we help ensure our code quality is improving, not declining, and that we can trace the source of bugs back to specific commits which introduced them.

Iโ€™m highlighting this topic because many professional services now actively support PHP, whether as their only language, such asย RIPS, or as part of the languages which they support.

Moreover, this is significant, because for a long time PHP always seemed to be an afterthought in deference to โ€œmore respectedโ€ languages, such asย Python,ย Java,ย C/C++,ย C#, andย Perl. Now, almost every professional static code analysis service supports PHP.

As a side note:ย Codacyย supports PHP as part of their offering.

Testing as a first-class citizen

The final reason why I believe the state of testing in PHP in 2018 is extremely positive, is that testing is a first-class citizen. I make this assertion for many reasons.

Firstly:ย all the leading frameworks support it. Fromย Laravel,ย Zend Expressive, andย Symfony, toย Phalcon,ย Yii,ย FuelPHP, andย Auraย (just to name a few) all make it painfully easy to test applications which are built upon them.

Secondly:ย because of discussions on testing. If you go to any major conference, whether community or commercial; if you go to PHP meetups; if you read PHP magazines and blogs, youโ€™llย read,ย see, andย hearย content about testing.

Whether youโ€™re new to PHP or new to testing, whether youโ€™re a more seasoned developer or tester, thereโ€™s content for you. You will always have an opportunity to begin, as well as to further build your skills.

Once, I agree, testing in PHP was seen as an afterthought by many. However, those days are gone.

Itโ€™s a testament to the hard work of manyย people

The state of testing in PHP has come along way and is, at least in my opinion, as good as any other language. That said, it would not be where it is today without the hard work of many in the community, but in particularย Chris Hartjes (the Grumpy Programmer)ย andย Sebastian Bergmannย (the founder of PHPUnit).

Chris Hartjes, the Grumpy Programmer.

Letโ€™s start with Chris (Iโ€™m slightly biased as I count Chris as a friend). Heโ€™s been banging the drum for PHP developers (as well as developers from all software development communities) to test their code for years.

Whether throughย his books,ย his PluralSight course, his conference speaking, orย his Twitter presence, heโ€™s been a tireless advocate for better testing for a long time now. Speaking from personal experience, I know I wouldnโ€™t be testing my code as much as I do if it werenโ€™t for his encouragement.

Sebastian Bergmann, creator ofย PHPUnit.

And to Sebastian, well what can you say, he created PHPโ€™s de facto testing tool, PHPUnit.

If it werenโ€™t for how easy PHPUnit is to install, configure, and use and for how feature-rich and flexible it is, Iโ€™d suggest there would be a lot fewer PHP developers testing their code than there is today.

Whatโ€™s more, PHPUnit has laid the foundation for a number of the testing tools and frameworks that followed it, includingย Codeception,ย Mockery, andย Behat. Iโ€™m not suggesting it did this directly, but I would suggest it helped make them possible.

Sebastian has been a tireless advocate of testing, whether through his writing, his conference speaking, or all the other ways in which he advocates for testing. So thank you to these two stand-out individuals. I know weโ€™re all better off for their ongoing efforts.

And Thatโ€™s aย Wrap

This is a broad overview of the state of testing in PHP today. While many are quick to predict the demise of PHP, I believe now is one of the best times to use the language.

In addition to a language that is virtually as rich and mature as any other, PHPโ€™s testing infrastructure makes it possible to develop rich and well-tested applications.

Whether youโ€™re using PHPโ€™s de facto tool, PHPUnit, or one of the others, such as Behat, Codeception, and Mockery, or whether youโ€™re using several of them in combination, you have so much high-quality choice.

Combine this with a reduced need to test, because of PHPโ€™s adoption of static type hinting, and those who, in the past, have hated on PHP, claiming itโ€™s a double-ended hammer should revisit those previous assumptions and see theyโ€™re no longer valid.

If youโ€™re a newcomer to PHP, what testing tools have you used and what successes have you had with them? If youโ€™re an old hand, what combination of tools do you use, and why?

Find out more about Bitbucket Code Review


Codacy is used by thousands of developers to analyze billions of lines of code every day!

Getting started is easy โ€“ and free! Just use yourย ย GitHub, Bitbucket or Google account toย sign up.

GET STARTED

2 COMMENTS

  1. excellent writeup. You covered all the giants really well and even shout outs to some of the folksinvolved. If you want to try some unit testing with something lighter weight, checkout https://github.com/bitslip6/tinytest. Single file test suite, supports data providers, code coverage (xdebug not required), expected exceptions, code annotations, etc.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Subscribe to our newsletter

To be updated with all the latest news, offers and special announcements.

Recent posts

Pulse end of Open Beta and new pricing

I'm excited to announce weโ€™re introducing a new pricing model to our Pulse product. Since we launched Pulse, weโ€™ve...

Accelerate book summary and key findings

I find myself explaining the value of adopting outcome-based engineering analytics every day, using the Accelerate book as the definitive reference...

The 4 main types of technical debt

Technical debt is a common metaphor for software's accumulated backlog (like bugs, missing documentation, and legacy code). It can happen because...

Introducing Codacy Labs: our experimental playground

Listening to customers is what makes your product thrive. At Codacy, we deeply care about our customer's needs and that's why we...

May Product Update ๐Ÿš€

Hi there ๐Ÿ‘‹, Here are a few product updates from May that we've been working on to...