Learning how to write tests for Drupal

Red and green traffic signal lights, with the green light glowing.

One of the goals I am working on is learning how to write tests for Drupal. I have been collecting resources on how to do so, and I thought others might find these resources useful too.

My journey to writing tests

I started getting involved with contributing to Drupal core development because I wanted to improve a number of items related to front-end development. As I have worked to do so, I keep falling further and further down the rabbit hole, where I find myself needing to learn more and more development techniques that typically fall under what is considered back-end development.

One of the barriers I have run into more than once in the issue queue is needing to have tests for a patch that in one way or another helps to make Drupal better for front-end development. Or really, for any type of improvement you are looking to make for Drupal. My inability to write tests for patches has meant trying to find somebody else who can do so. That's not always possible, and it can really slow down efforts to move a patch forward.

Tests for adding image styles

I most recently ran into this when working on a Drupal 8 issue that would allow images added through CKEditor to make use of image styles or responsive image styles. You can take a look at this issue for adding support for image styles/responsive image styles. We almost had this issue ready to be added right before the release candidate for Drupal 8. Unfortunately we couldn't get the issue in, because we didn't have tests for the patch.

Thankfully the Drupal 8 cycle allows us to continue to add new features throughout the D8 development cycle, in particular at major releases, which come out every six months. For the first major release, 8.1, there was a brief six-week window where patches could be added for new features. I was traveling a lot at that time and didn't manage to work on this issue during that window. I was also still pretty burned out from the rush to release D8. I hoped that we might be able to get this issue in during the window for 8.2, which will be released this fall.

Assistance at extended sprints

At DrupalCon New Orleans, I attended the extended sprints on the weekends on either side of DrupalCon week. I was determined to get this issue completed. Thankfully there were a lot of great mentors who helped me work on the issue, so I could get the patch in better shape in order for tests to be added. That meant refactoring the code to make better use of dependency injection and smaller, more testable methods. With some really great assistance from a lot of experienced core developers, I got tests added to the patch, and I was hopeful it might be almost ready to go. However the patch received a lot of feedback, and it was clear there was a lot more work to do.

I admittedly got discouraged at that point. It can be hard to find time to work on contributing to core, and it seemed like there was so much work more to do. Plus it was clear that I did not fully understand how to write tests for Drupal. I had followed some examples, but I didn't really understand the concepts and patterns.

Investigating how to write tests

So I decided to set a goal for myself to work to really understand how to write tests for Drupal. One weekend I got the urge to look up sessions from DrupalCons on how to write tests... and that's when I got a bit carried away. I ended up looking at the sites for all previous DrupalCons and collected links to all the sessions that had something to do with writing tests.

The Writing Tests for Drupal repo

I collected all these links to videos and slides, as well as some articles and documentation pages, into a Github repo, Writing Tests for Drupal. My hope is both that others will find this information useful, and that others will contribute useful resources they have found. In time maybe this can help guide others to improve their abilities to write tests.

Increasing the number of people who can write tests would be a big boost to velocity for core. Very often, lack of knowledge of how to write tests slows down or halts progress on issues. We can do better.

TestCamp?

In a recent conversation with Wim Leers, I half-jokingly suggested it would be great if we could have a DrupalCamp specifically dedicated to learning how to write tests. I called this Test Camp. A number of people seemed to react positively to the suggestion when I mentioned this on Twitter. I am not sure what it would take to make that happen, but I could see that being very helpful. Perhaps one or two days of a single-track set of sessions with guidance on the theory behind how to write tests, along with at least a day of sprinting where attendees could work with mentors on how to write various types of tests. In fact I found that such an event had actually happened at DrupalCon Szeged in 2008. So maybe it's not impossible to make something like this happen again.

Making a plan

What I find particularly challenging is not only learning the code patterns necessary to write tests, but also how to come up with a particular testing strategy for an issue. How do you determine what types of tests are needed and what things should be tested?

A few things I have learned about writing tests for Drupal

I have tried to make headway in making sense of this, and here are a few things I have learned:

  • Make sure you write your code in a way where it can be tested in the most efficient way possible. With Drupal 8, that means using dependency injection to bring in services you need, so that you don't need to mock those services in a unit test.
  • Unit tests allow you to check if a particular method does what is supposed to do. These can run very quickly if the code is written in the right way, because you do not need to build a Drupal site to run the test.
  • Functional tests or Integration tests check that the code you wrote actually works in the browser. These tests usually run more slowly, because an entire Drupal site db needs to be built and fired up in a browser. Think about how long it takes to do so when you do a Drupal site install. Even with drush si, doing a site install on the command line can take a short bit.
  • Kernel tests fall somewhere in between the two: while they require a Drupal site db to be created, they do not need to be run in a browser, which is a little faster.
  • Drupal 8 now not only has web tests which run a test site in a simulated browser, but also now has browser tests, which can also test that certain JavaScript behaviors are working correctly.
  • Visual regression tests can be useful in a project to check that a site still appears the same after a code change, which can be particularly useful in ensuring that a CSS or HTML change does not cause a problem elsewhere in the site.
  • Behavioral tests using tests like Behat can be really useful in a project to check that a certain site feature works the way it should. This is essentially a functional test, but often written in a natural language syntax that makes it easier for non-coders to write tests. This seems particularly useful for client projects.

SimpleTest

Drupal originally made use of the SimpleTest testing framework. This was a contributed module in Drupal 6, and then was incorporated into Drupal core in Drupal 7. One interesting thing I found through looking through older resources is that SimpleTest was originally intended more for unit testing, testing discrete parts of code. However in practice these were more like kernel tests. Because of the procedural nature of Drupal 6 and Drupal 7, isolating individual methods without having to mock global functions could be very difficult. So over time, SimpleTest grew into being used more for functional tests.

Don't dismiss some of the older resources in the Writing Tests for Drupal repo! These are some of the only presentations you will find on the basic principles of writing tests with SimpleTest. Many later presentations assume you already know how to do so.

PHPUnit

Drupal 8 introduced PHPUnit for test writing. As the name implies, this initially was geared towards writing unit tests. However, it has also been adapted for writing kernel tests, web tests and browser tests. So going forward, writing tests for PHPUnit is generally what you will want to do.

Learning more about tests

This brief summary of things I have learned is not intended to be comprehensive or authoritative. It's just my best attempt to summarize a few things I have learned so far from reading articles, reviewing slides and looking at docs. I still have yet to watch the presentations I have found, although I am looking to do so.

Hopefully in the next few months writing tests is something I can get more confident in, and if it interests you, I encourage you to try to learn more too.

And if you have suggestions for ways to improve the resource list in the Writing Tests for Drupal repo, I encourage your contributions!