paint-brush
The Developer’s Guide to PHP Testing in 2018by@hackernoon
8,776 reads
8,776 reads

The Developer’s Guide to PHP Testing in 2018

by HackerNoonJune 11th, 2018
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Testing code is an essential aspect of writing software of any level of quality.<br>It’s essential because it helps us know that the code works as it should; whether that’s a specific unit of functionality or the application as a whole from the perspective of the end user.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - The Developer’s Guide to PHP Testing in 2018
HackerNoon HackerNoon profile picture

By Engineer Matthew Setter

Disclosure: Codacy, the automated code reviews platform, has previously sponsored Hacker Noon. Use code HACKERNOON for 15% discount. This post originally appeared on the Codacy Blog.


Testing code is an essential aspect of writing software of any level of quality.It’s essential because it helps us know that the code works as it should; whether that’s a specific unit of functionality or the application as a whole from the perspective of the end user.


So how is PHP faring in 2018? What’s the state of testing in PHP in 2018?In this article, I’m going to answer that question from a variety of perspectives.

From testing languages to people working behind the scenes, I intend to show you that 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 that 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 that you have to supply a string and that 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 = <<<EODmodules/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 = <<<EODmodules/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 that they only need to supply string test data.

There’s no need to supply data of any other data type, as the language ensures that 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 that they should always be used. I agree that 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 that only strings are supplied to the function. Given that, you would have to add a series of tests to ensure that 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

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.

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 basketIn order to buy productsAs a customerI 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, that said, after getting over that initial hurdle, I have found it an excellent tool.

Codeception

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

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 its de facto standard.

Having a quick glance at the manual shows you that it has significant functionality. So it should come as no surprise that is 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; and
  • 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, now 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 that 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 that 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).

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 that I wouldn’t be testing my code as much as I do if it weren’t for his encouragement.

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 that 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 that it did this directly, but I would suggest that it helped make them possible.

Sebastian has been a tireless advocate of testing, whether that’s through writing, 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

That’s a broad overview of the state of testing in PHP today. While many are quick to predict the demise of PHP, I believe that 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 that 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 that 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 which tools do you use, and why?

Find out more about Bitbucket Code Review

This post originally appeared on the Codacy Blog. Codacy, Hacker Noon’s weekly sponsor, automates quality standards and code reviews on every commit and pull request so you can ship two days earlier on every two week sprint. Use code HACKERNOON for 15% discount.