Had a client call last week. They’ve got this huge, old WooCommerce plugin that’s been passed through three different dev teams. A new junior dev on their team pushed a small change to how shipping is calculated, and suddenly, random discounts were being applied during checkout. Total mess. But only for certain products, and only when the moon was in the right phase. You know the type of bug.
This is the exact moment when you realize you can’t trust the codebase. It’s fragile. And it’s why we need to talk about WordPress unit testing, especially on projects that weren’t built with testing in mind from day one. Which, let’s be honest, is most of them.
Your Code Is Probably a Nightmare to Test
My first thought was to just find the logic bug, patch it, and get out. The classic quick fix. But I’ve been doing this for 14+ years, and I know that’s just putting a band-aid on a bigger problem. The real issue was that a small change over *here* could break something completely unrelated over *there*. The codebase had zero safeguards.
Most WordPress code, especially older stuff, is a tangled web. You have functions that do five different things, rely on a dozen global variables, and directly call `get_option()` or `update_post_meta()` everywhere. How are you supposed to test a function like that in isolation? You can’t. Not without a ton of work, anyway. Here’s the kicker: you have to break it apart first.
Start With a Single Bug
So instead of trying to boil the ocean and test the entire plugin, we focused on that one discount bug. The strategy is simple: make the bug repeatable with a test. First, you write a test that fails because the bug exists. Then you fix the code, and the test passes. That’s it. That’s the win.
For example, let’s say the buggy function looked something like this—a simplified version, of course.
function calculate_special_discount( $cart_total, $customer_id ) {
// Some complex logic that was breaking...
if ( $customer_id > 1000 && $cart_total > 50 ) {
return $cart_total * 0.85; // Supposed to be a 15% discount
}
// Whoops, a dev added this and it broke things
if ( get_user_meta($customer_id, '_special_customer', true) ) {
return $cart_total * 0.50; // Accidentally giving 50% off!
}
return $cart_total;
}You can’t easily test this because of that `get_user_meta` call. You’d have to refactor it to make it testable, maybe by passing the user meta in as a parameter. The point is to isolate your logic from WordPress functions. This idea is foundational, and I saw a great discussion on it over at carlalexander.ca, which is worth a read.
So, What’s the Real Takeaway?
Don’t try to write tests for your entire existing WordPress project at once. You’ll burn out and give up. Instead, do this:
- Test the Bugs: The next time you fix a bug, write a failing test that reproduces it first. Then, make that test pass. You’ve now created a safety net that prevents that specific bug from ever coming back. This is called regression testing.
- Test New Features: Any new code you write should have tests from day one. It’s way easier to write testable code from scratch than it is to refactor old code to make it testable.
Over time, you’ll build up a suite of tests that covers the most critical and fragile parts of your application. The goal isn’t 100% coverage. The goal is confidence. Confidence that your next deployment won’t break the entire checkout process. Period.
Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.
Leave a Reply