When I talk about writing automated tests for WordPress plugins with other developers, I often hear that they’re not sure what to test first. I find the uncertainty around what to test first is a major blocker for writing tests. This post will address this concern.
The other two big concerns I hear about are “I don’t know how to write tests” and “setting up testing is a pain.” I used to agree with that last argument, then I built Plugin Machine. If your issue is the first one, check out my YouTube videos about how to write tests for WordPress plugins.
One of the most useful blog posts about testing is called “Write tests. Not too many. Mostly integration.” That post, which I strongly recommend reading, is not written in the context of PHP development. In this post I’m going to show two approaches to testing I have used that are inspired by this idea. I hope it answers any “what should I test first in my WordPress plugin” questions you make have.
All Code Is Testable
Before getting into what tests to start with, I want to address one additional concern I hear. Many developers belive their code isn’t written to be “testable.” I belive that this grows out of folks conflating unit tests with tests. Writing unit tests that are totally isolated from WordPress, MySQL and other dependencies is hard with WordPress for sure, but unit tests are not the only kind of tests.
There are other types of tests we can write. This post makes two recommendations. The first uses integration tests, the second acceptance tests. Once those test are in place, you should feel comfortable refactoring your code. When you do that, it may make sense to write unit tests for the new code. Either way the integration and/ or acceptance tests make the refactor or any smaller changes more safe.
Most of the time when I do WordPress plugin development I rely mainly on integration tests, instead of unit tests. My friend Carl’s opinion on this is reversed. He writes mainly unit tests, and relies on mocks.
Write Integration Tests First
Recently I was working on a plugin for a client that added a shortcode. I wrote two integration tests to start. They both did the same thing: assert that the output of the shortcode is not empty. Since the shortcode uses very different logic for logged in users vs non-logged in users, one test that runs with a logged in user and one runs without.
This is a plugin I created with Plugin Machine. I enabled the “WordPress Tests” option so I had tests that run with WordPress loaded in local development and Github actions I could work with.
Here is a simplified version of what the class being tested looks like:
My tests call the “callback” method directly. I considered using do_shortcode() in my tests, but that would have been more complex, and accomplished the same thing. Instead I just checked the output of the method:
Once I had those tests in place, I ran them and got a bunch of fatal errors. I had written the plugin real quick without ever running it. So, I worked on getting the tests to pass, which got the plugin closer to being complete. More importantly, for the next steps I had some tests to show us if anything had gone super wrong.
Some Tests Are Better Than No Tests
After I got those tests to pass, I put the shortcode in a post and loaded it. I got another error after I interacted with the process the shortcode added to the site. That’s where more detailed unit tests might help, but I’m glad I didn’t start by writing isolated unit tests for each part of the code.
The point of this is to say not only are some tests better than no tests, but also that too many tests can make it harder to refactor. If I had to write a test for every method of every class, before making changes to most of the classes, I would also have had to rewrite those tests.
Instead I stuck to a few integration tests to make sure everything worked together. It’s not perfect, but it provides more safety than having no tests, without taking too much time to write or to run.
Starting this way doesn’t mean I can’t write more tests later. In fact it makes it easier to.
Browser Automation Tests Are Great First Tests
A real weakness of the approach I just explained is that I can’t test interactions with the HTML. I was only testing that HTML was generated without an error. That HTML outputs a form, and the kind of test I was using doesn’t work with a browser.
Browser automation tests are often used to create “end to end” tests. These tests let us emulate how a real user interacts with our code.
These tests cover a lot of parts of code. For example, if you test submitting a form, that test might cover all of these things:
- That the form HTML is generated properly.
- That the submit handler for the form works as expected.
- That the form is processed as expected, or rejects invalid
- That whatever runs when the form is submitted works correctly.
- That the form shows validation messages, error messages and redirects properly
There are many ways to write and run these types of tests, using JavaScript, PHP or no-code editors. Here are some recommendations:
- WordPress e2e Tests – Write tests in Node.
- cypress– Write tests in Node.
- Behat with WordHat – Write tests in PHP.
- Codeception with WP Browser – Write tests in PHP.
- Ghost Inspector – No code, write tests with a Chrome extension.
- Checkly – Low-code, create tests with Chrome extension or write in Node.
Now Write Some Tests
I hope this post motivates you to get started with tests. You can’t get full test coverage in a day, but any tests will help. Plugin Machine makes getting started with automated tests simple. If you need more help, I offer automated testing coaching. Learn more here.
Featured Image from WordPress photos, by me — Josh Pollock. License CC0.