In a few recent projects, I’ve been unit testing WordPress code and doing more general test-driven development than normal. I’m no stranger to TDD, but it’s not something I am religious about using. For me, it depends on the nature of the project.

There’s a lot of writing on TDD and its advantages, and a lot of people who use it swear by it. It builds a level of quality into a project and helps with adding new features, solving bugs, and modularizing code.

Unit Testing WordPress

Unit testing WordPress code is a bit of a mixed bag, and it comes down to the fact that object-oriented code in WordPress is often tightly coupled to both the business logic and the WordPress API.

Since TDD can help designing the architecture of a project, it can help guide how we can create more testable classes.

Unit Testing WordPress Code

When I was working on the WordPress Plugin Boilerplate, one of the classes that I included (and that’s still part of it) is the Loader class.

This class was responsible for registering various functions with hooks. Ultimately, it allowed for decoupling functionality specifically for tying functions into WordPress and functionality specifically for completing the business logic of a project.

And this is something that still contend is the way to go.

1. Business Logic

When writing code, business logic or domain logic refers to the part of the code that helps to solve the specific problem at hand.

These classes usually encapsulate ideas represented by the problem and the attributes and functions necessary to solve them. They will likely be (or should be) a collection of classes that communicate with one another and that break the solution into several, manageable parts.

Regarding WordPress, none of these functions will communicate with the hooks or anything like that. Sure, they may talk with several of the WordPress APIs, but they aren’t going actually to register any of their functions with WordPress.

Usually, that sits outside of solving a specific problem and creates unnecessary coupling between the solution and WordPress itself. Instead, you want to make sure that the code that binds your algorithms with WordPress are separate from the code that solves the problem.

2. Registering Code with WordPress

Registering code with WordPress does not mean that we ignore or forgo testing code that uses the WordPress API. It does, though, mean that we separate testing code that uses add_action or add_filter into a separate class (or a separate set of classes).

These particular calls tie your code to WordPress, and though it’s important to have functions tied to, say, certain filters to WordPress, we should be more concerned about what the function is doing rather than if it’s safely tied to WordPress.

To be clear, I’m not saying that we should never test if a function is separate from any of the WordPress hooks. Those functions should reside in a set of tests that are strictly designed to make sure the functionality is bound to the core application.

I do think, though, that it’s more important to test code specific to a problem domain rather than if a function is properly registered with a hook.

It’s easier to test manually that a function is tied to WordPress, and it’s less likely to change once it’s properly registered rather than code that is working on any input or code related to a specific problem.

A Layered Approach

If you’ve ever worked with .NET or Rails or another type of framework, then you’re likely familiar with an object-relational mapping system (or an ORM).

Simply put, this is a layer of software that allows us to work with information stored in the database in the application layer.

It maps rows and columns to classes so that we can literally work with the database in terms of objects. They also provide a level of data validation, sanitization, and other helpful functions.

One way of thinking about this is in terms of a stack. For example:

  • the database is at the lowest level,
  • the ORM sits on top of the database,
  • the application layer sits above that,
  • and the front-end is at the top.

You can make this is detailed and as nuanced as you’d like, though.

Though it does have features that help us work with the database, WordPress doesn’t have a specific layer of code like this. That doesn’t mean that we can’t introduce it in our projects, though.

The two points mentioned above can be thought of in similar fashion. Rather than thinking about it as an entire section such as an ORM, think of them as two separate layers in the application layer.

One layer is for talking directly with WordPress, and one layer is for handling the business logic that solves the overarching problem the project is trying to solve.

As mentioned at the beginning, this would allow us to test the business logic completely independently of if, say, a script is registered with WordPress.

And yes, there are times in which certain data structures will need to be tested (such as an array that represents the menu in the dashboard). There are ways to do this through mock classes, mock data, and other strategies, but that’s beyond the scope of this post (though I aim to talk about this more in future posts).

Ultimately, the point is that although WordPress isn’t as testable as some other programming platforms that are available, that doesn’t mean we can’t do our part to make our code more testable.