October 20, 2014
Episode 28 is all about unit tests!
Unit tests are a tool that developers use to help ensure that code is performing properly. During this episode we discuss how to get unit tests set up, how they are valuable, and some common challenges that developers encounter while writing tests.
We began discussions on unit tests in Episode 8, now it’s time to go further.
This episode was sponsored by WP Ninjas, the creators of Ninja Demo and the highly popular Ninja Forms plugin.
Show Notes:
- WP CLI – Plugin Unit Tests
- Unit Tests for WordPress Plugins
- Curtis McHale and Unit Tests
- Travis-CI
- Scrutinizer-CI
- Review us on iTunes
BRAD: Welcome to Episode 28. Today we’re going to be talking about unit testing. But first, Pippin, what have you been up to, man?
PIPPIN: The last week or so was mostly involved with getting Affiliate WP version 1.3 out, which was a big release that Andrew and I have been working on for a couple of months. I think we pushed out 1.2 around July. Maybe it was August, so we’ve had a couple of months to work on getting some new features out. We finally got it all finished, and we’re pretty pleased with it.
BRAD: Cool.
PIPPIN: It was a pretty large release that had some highly requested features in it like people really wanted pretty affiliate URLs, so instead of something like yoursite.com?ref=3, it would just be yoursite.com/ref/BradTouesnard.
BRAD: Right.
PIPPIN: And that would be an affiliate link, so we got those put in. We got some — we added affiliate coupon tracking to iThemes Exchange, so instead of requiring an affiliate URL, you can now, if you redeem a coupon that’s connected to an affiliate, that affiliate will automatically get a commission on that sale even though no affiliate URL was used.
We added a new integration for Gravity Forms, so if you’re using Gravity Forms to sell stuff, you can now send someone through an affiliate link to your purchase form, then it’ll track that, and it will create a referral based on that if it’s valid. We’ve had Gravity Forms integration since version 1.0, but I was kind of a workaround. It wasn’t a really good integration because there were some missing hooks in the Gravity Forms plugin. Alex and the other developers over at Rocket Genius got those put in for us, so we were able to finally get that release pushed out, which was nice.
Beyond that, we got EDD 2.16 pushed out. That actually happened this morning. That fixed a couple of minor, but important bugs. That’s been pretty much my last week, and now moving onto the next things.
BRAD: Cool.
PIPPIN: How about you?
BRAD: We’ve been cracking away at the next release of Migrate DB Pro. It’s crazy. This release has quadrupled the number of issues in GitHub than the previous release.
PIPPIN: Is that just because you’re adding a bunch of new features or because you keep finding things that you need to work on or improve elsewhere in the code base?
BRAD: That’s the funny thing. When we do a release with a bunch of new features, it’s smaller, way smaller. Usually it’s four or five lines in the change log, right? But when we do one of these releases where we’re cleaning things up and we’re fixing bugs, we had Scrutinizer-CI. We cleaned up all the issues with that and the report that we get from Scrutinizer-CI with all the little problems that it identifies.
There are just so many things, and they’re not all little things either. Some of them are big compatibility issues that we had an issue with WP Engine that we’ve solved. Yeah, there are just a lot of different things, little things, so it’s not even a major release, but it feels like it was a lot of work. So it’s one of those, those ones. Have you ever had one of those yourself?
PIPPIN: I have.
BRAD: Yeah.
PIPPIN: I actually had that probably the first time I turned on Scrutinizer-CI for EDD.
BRAD: Right.
PIPPIN: Because it goes — Scrutinizer-CI, for anybody who is unaware of it, kind of goes through and scrutinizes your code base. It looks for unused variables, for typos, code duplication, tons of things like that. The first time I ran it, it reported something like 500 issues.
BRAD: Yeah.
PIPPIN: Now, those issues could be large or small. They might just be like, oh, you have a variable here and you’ve defined it twice in a big chunk of code, or it could be a misnamed variable, so a lot of times the issues are really, really minor.
BRAD: Right.
PIPPIN: But still, there were so many of them, so Dan and I spent a good few hours just going through and fixing all the ones that we could or figuring out ones that we needed to, even if we needed to fix them or we could just ignore them.
BRAD: Right.
PIPPIN: But we had the exact same experience.
BRAD: Yeah, a lot of those issues with Scrutinizer are cosmetic, kind of like code formatting stuff. But, yeah, every once in a while you’ll see one that’s like, oh, we’ve got to rework all this to get this fixed.
PIPPIN: Yeah. We found a couple of legitimate bugs through it too, as well as we found several areas that we had a lot of code duplication that we could just clean up.
BRAD: Right, yeah.
PIPPIN: It’s a really cool tool.
BRAD: It is. I love Scrutinizer. It’s great. Yeah, we’ve been working on that, and so that’s getting really close to release, just a few other things to fix up. We’ve also been working, started to work on the Amazon Web services plugins that we have. Well, we’ve got two. We’ve just got the core plugin that has the libraries and then the S3 and Cloudfront plugin. We’re getting that all cleaned up, the free version of it cleaned up, and then we’re going to start working on the pro version, which will just be an extension of that, that plugin.
I don’t know if you saw, it, but I’ve been working on the UI for it because that’s one of the things; that’s one of the problems with it. It’s just kind of confusing, the setting screen, so I’ve been working on that a bit. I posted it on Twitter to see what people thought, and so far so good, some good feedback.
PIPPIN: Very cool.
BRAD: Yeah. Unit testing, man, what’s that all about?
PIPPIN: Unit tests are really pretty cool. Okay, so for anyone who doesn’t know, a unit test is a tool that we use in development to test small chunks of our code. Let’s say that you have a function, and that function performs a calculation and returns a result. You might have a unit test that tests whether that function is working properly. You basically say: Here is the function that I have. Here’s the value I want it or expect it to return. Now tell me if it does.
A unit test is basically testing the smallest unit, the smallest chunks of code that we can. It’s a really powerful tool in development because it’s like having someone watching your back. If you write unit tests for all of your code, and if you run them any time you push our a release or every time you commit to your code base, you can have it basically do an automatic check throughout all of your code to see if things are still working the same way that they are.
It’s really, really useful, and it’s something that helps you get better and better at development, for one because you have to learn how to write testable code. Anybody who doesn’t really know what unit tests are, I know that that little explanation wasn’t great. Check out PHPunit.com, and also just the Wikipedia page on unit tests because every single programming language, or not necessarily every one, but a lot of them, have unit tests. PHP Unit is one of the primary tools that we’ll use inside of PHP.
BRAD: Right. I think the reason why unit testing is important is that, if you do a refactor of a function, for example, and there’s a unit test for that function in place, and you refactor the function, and you don’t change any of the outputs of the function, you’re just refactoring it maybe for cosmetic purposes or maybe you’re refactoring it so that it’s easier for people to understand what the function is doing, but you’re not really changing the inputs or the outputs of the function, and then you commit that, you run your unit tests, and the unit test complains because some test is failing, right, on that.
PIPPIN: Right.
BRAD: That’s awesome because you didn’t catch that in your own testing or your visual inspection of the code, but your unit tests just caught it.
PIPPIN: Yep.
BRAD: That’s a very, very simple example.
PIPPIN: Let me give a quick example of that for people that aren’t necessarily familiar and might be a little help. Let’s say, okay, so I work in ecommerce a lot, so this is something that definitely applies to me. But let’s say we have a function that calculates your tax rate and just do some really simple math. Let’s say that your tax rate is 10%, and your purchase, your pretax amount is $100. On 10% tax, that means our final total should be $110.
What we can have is we can have a really simple function. Let’s just say we have a function that says calculate tax on subtotal. That function should return $10 on a $100 purchase if our tax rate is 10. One of the things that we can do with unit tests is have a test that tests whether or not that function actually does return $10.
One thing you might do is say: okay, function, I have $100 purchase. What is the tax on it? Here’s $100. Do I get $10 back? Yes, I do. Excellent. My test is working.
What if I pass it $100.01? Do I still get $10, because we have to think about rounding? What if I pass it $100 and $0.000057? Do I still get $10 back?
One of the things that a unit test can be really, really helpful here for is seeing if your function to calculate your tax returns the same expected value even when you pass it a whole bunch of different numbers. If you pass it 90, do you get 9? If you pass it 80, do you get 8? Then you could try changing things up, like what if you set a tax rate of 9.5%? Do you still get $9.50 on a $100 purchase?
BRAD: Right.
PIPPIN: That’s where unit tests can be really, really helpful, especially in things like ecommerce when rounding, maybe you’re not always rounding to two decimal places. If you’re selling with Bit Coin, you’re rounding to eight decimal places, so having unit tests to set up these functions that are doing these calculations are really helpful.
BRAD: Mm-hmm, yeah. That’s a really great example, actually, because that really illustrates all the different scenarios that you could end up with for that.
PIPPIN: Well, I can’t even tell you the number of times that we’ve pushed out an update, and then somebody comes back going, oh, the tax doesn’t calculate right now. And it turns out because we were rounding the decimal places too early or too late, or something like that.
BRAD: Right.
PIPPIN: That’s where your unit tests really help you.
BRAD: Right.
PIPPIN: If you take the time to set them up, so speaking of that, Brad, how do you go about getting unit tests set up? How do you get started?
BRAD: I think WP-CLI is probably the best way to get started. We can link this up in the show notes.
PIPPIN: Yeah.
BRAD: But if you Google search WP-CLI unit testing, they have a really nice little guide to get started in a few command line commands.
PIPPIN: Yeah. I used it really recently. It’s excellent.
BRAD: Yeah, yeah, so I would recommend just going through that. Just use the sample plugin that they have, just run it, and just kind of get a feel for it. See what it feels like. See what it’s like. Then I’m sure there are plenty of tutorials out there. There’s probably screen cast too. Is there any that you would recommend, Pippin, while you’re investing this?
PIPPIN: Well, along with the one from WP-CLI, Curtis McHale has been doing a series on it recently, which has been really good. Brian Richards is getting ready to do a unit testing series on WP-Sessions. I’m not sure if he’s started that or not yet. I’ve been doing a little, a small series on it.
BRAD: You have been doing a series.
PIPPIN: From my site too, yeah, so I’ve been doing a small series. Basically, I wanted to step back to the basics and look at how do we get unit tests set up. Here’s step one. I don’t know what WP-CLI is. Okay. Let’s get that set up. I don’t know what PHP Unit is. Let’s get that set up.
BRAD: Right.
PIPPIN: It’s specific to setting up….
BRAD: Two steps backward for one step forward.
PIPPIN: Yeah, pretty much, so that’s on my site, and that’s free for everyone. It’s on the homepage right now. That actually uses — the tutorial from WP-CLI is used pretty heavily in mine, so you’re going to see both of those if you go there.
Another one is, once you start playing with it, if you get WP-CLI up and running, which is really pretty easy as long as you’re on either Linux or Mac. It’s a little bit more difficult on Windows. But once you get up and going, go and look at other plugins that have unit test. Look at WordPress Core, and just kind of see what they’re testing. See how they’re writing their unit test and things like that because that’s really going to help.
I think one of the issues that people run into a lot with unit test is, great, I have my unit tests set up. Now what do I do?
BRAD: Right.
PIPPIN: Because it turns out that you can’t — just because you’ve written a plugin does not necessarily mean that it’s written in a way that makes unit tests possible. You have to be able to write testable code.
BRAD: Mm-hmm.
PIPPIN: Brad, what would you say are some of the main things that determine whether or not you have testable code? What are maybe some just main tips?
BRAD: Yeah. This is funny because I find WordPress is actually pretty bad of code to be unit tested because of its use of global variables. Really, what you want is all of your inputs coming into the function through an argument or several arguments in the function. I find that makes it a lot easier to know what’s coming in, and then know what’s going out.
But there are definitely ways around it. I mean, the way WordPress unit tests are set up it sets the globals before it runs the test. But it’s just a little bit harder to know what globals that you need to set to test that function, right?
PIPPIN: Yep.
BRAD: You’re writing your own code. You can control that yourself, so I would suggest trying to avoid using global variables as much as possible.
PIPPIN: I think another one —
BRAD: Andrew Nacin has a great post about all of that, actually.
PIPPIN: He does.
BRAD: I’ll have to link it up in the show notes.
PIPPIN: I think he might have done a WordCamp presentation on it too, which if he did, is probably on Apple.tv. Sorry, not Apple.tv – WordPress.tv.
BRAD: Yeah. We’ll link that one up if we can find it.
PIPPIN: I think a great plugin to look at as an example of how to write testable code is bbPress.
BRAD: Oh, yeah? Hmm. Why is that?
PIPPIN: The reason — okay, so when you’re writing code, if you want to write code that’s testable, you have to have a return value, pretty much, in general. You have a function that returns a value.
BRAD: Mm-hmm.
PIPPIN: What a lot of people will do is they might write functions that echo values as well.
BRAD: Right. Yeah.
PIPPIN: Just like display functions, so think of a WordPress example. The Title or The Content are functions that display and output the value. They don’t return it to a variable.
BRAD: Mm-hmm.
PIPPIN: They have options too, like there are parameters you can pass. But in order to write a test, you have to have a function that will return a value because you’re going to say some thing like expected value is this, and you’re going to call a function. Sorry, the value I have is this, you’re going to call a function, and then you’re going to say my expected value is this. You have to be able to compare them. You can’t necessarily do that if it’s actually displaying. The reason I think bbPress is a really great example is because it is extremely consistent in having get functions and display functions.
BRAD: Right.
PIPPIN: It has a function — any time it displays the title of a topic, it has bbp_get_topic_title, bbp_thetopic_title, and it has that for every single function throughout the entire code base. If you can get into that kind of habit, it’s going to make testing your code a lot easier.
BRAD: Right.
PIPPIN: When we were setting up the unit tests for Easy Digital Downloads, we actually ran into an issue. We have a small rest API in the plugin, and we realized that we’d actually written the entire API in such a way that we couldn’t write a single unit test on it because of the way that it was getting all of the data and doing things like that, and that was kind of frustrating because then we had to go back and rework it. And it’s still not entirely testable.
BRAD: Right. Another, like when I said global variables, I mean that really encompasses all globals, including post variables, right? Instead of having the post variable, like $_post, using that variable, instead of doing that maybe you put that variable into your function through a parameter instead. I find that’s something I see a lot that makes it just a lot harder to test because, in your unit tests, then you have to set the post variable, and it just looks weird to me. It just seems a little ugly, to be honest.
PIPPIN: Yeah. I find one of the more difficult things with the test and unit tests are logged in user behavior is pretty difficult to test.
BRAD: Because you’re setting cookies and stuff?
PIPPIN: Yeah.
BRAD: Right. Yeah. I mean, it’s not going to be perfectly clean, your unit tests. There is going to be ugliness to them like that because you’re emulating. You’re basically emulating real world, someone using a browser, right, to run your code, right? You’re kind of emulating that in some scenarios. Isn’t there ways in the PHP Unit framework to test output, so search for string within the output?
PIPPIN: Yeah.
BRAD: Isn’t there a place to do that?
PIPPIN: I don’t know if it’s the proper way to do it, but what I’ve always done is just use output buffers.
BRAD: Right.
PIPPIN: What you can do, if you have a function that outputs a value instead of returning a value, you can set up an output buffer before you actually run the function. You start the output buffer, run the function, and then —
BRAD: Capture the content.
PIPPIN: — capture the contents of the output buffer and then look at that. What we’ve done in our EDD unit tests quite a bit on some of those, like, we have tests that are related to template files.
BRAD: Right.
PIPPIN: And so we want to check and see whether or not the content of our template file came in properly.
BRAD: Right.
PIPPIN: And so what we’ll do is we’ll set up the output buffer, capture the output in that buffer, store that in a variable, and then look to see whether or not there’s a valid HTML string there.
BRAD: Right.
PIPPIN: It’s not super clean, but it does work.
BRAD: An example of that one would be, like in EDD, you might want to test the receipt, which is pretty important, the email receipt template I guess would be.
PIPPIN: Yeah, that’s exactly right.
BRAD: Yeah. Yeah, that’s pretty important that people get the correct receipt, right?
PIPPIN: Just a little bit.
BRAD: Yeah. Cool. What are the challenges with unit tests? You write them as you’re coding, and then sometimes you might forget to write them, right?
PIPPIN: Yeah.
BRAD: Does that happen with you guys?
PIPPIN: Absolutely. I think one of the biggest challenges is keeping your unit tests up to date. Every unit test is great, and every unit test that you get added is awesome. Every test you can add is great. If you can add five tests, great. If you can have 100 tests, even better. But what’s hard is keeping your code base and your tests in synch.
It’s really easy to write a function or write a new class or something like that and not write any unit test for it. Just be like, okay, we’re going to commit this, we’re done, and we’ll write tests for it later. But what happens then is that that code usually doesn’t ever get a unit test written for it.
BRAD: Right.
PIPPIN: I don’t know what WordPress Core or other major projects that have unit tests on them have in terms of their overall code coverage, but it’s usually really, really low.
BRAD: Yeah.
PIPPIN: I think, EDD, we were thrilled when we managed to pass 40% code coverage. Now I think we’re back down to maybe 30%.
BRAD: Right. Huh.
PIPPIN: In this case, for anyone who doesn’t know, code coverage would be the percentage of our code that is covered by a test. If you have 100 functions, if you have 30 of them covered, you have basically 30% code coverage, and so it can be really hard to keep your code base up to date. Something that I found that helps a lot was to always, just kind of have the mentality that says if we write a new function or we write a new class, it does not get committed until there is a unit test to go along with it.
BRAD: Wow! Okay.
PIPPIN: It doesn’t always happen.
BRAD: Yeah, yeah.
PIPPIN: Guarantee you it doesn’t happen, but at least have the mentality that says we should be doing this.
BRAD: Yeah. That’s what we’ve pledged to do. I remember I wrote the email that said, okay, we’re going to hold each other accountable during our code review process. If you notice that there’s not a unit test accompanying the pull request, sound the alarm and send it back to the developer to make sure that we get code coverage there, and it’s just so hard to stick to it when you’re kind of trucking along, slinging code, right?
PIPPIN: I think WordPress Core has been getting really good at that in terms of requiring unit tests with all new changes.
BRAD: Yeah.
PIPPIN: Since maybe it was some time during 4.0 or 3.9, but especially like Scott Taylor has been amazing with this saying we’re going to have a unit test with every single update.
BRAD: What was happening there? Did he become the unit testing police? Was he going around to–?
PIPPIN: I think he just decided to take it on himself to say I want to improve our unit tests.
BRAD: Right, but I mean — oh, okay. So he was writing the tests, was he?
PIPPIN: Well, he was doing both, so he was writing the tests, but also if somebody submitted a patch, he would go in and say, “Hey, it would be really awesome if we could get unit tests along with this patch.” He was encouraging people to do it.
BRAD: Yeah, that’s probably what we need in our team. We need someone to own it. I’m like the unit testing police, and everyone has to write unit tests.
PIPPIN: Will abide by my rule.
BRAD: Yeah, exactly. But, I mean, you’ve better off in the long run, right? Everyone is better off in the long run if your tests are covered, right?
PIPPIN: Oh, absolutely. I mean, for the first maybe six months or so that we were building unit tests into EDD, we didn’t really — I didn’t personally see that much value in it. I thought it was cool, but I was like, why does it really matter? We know if our code is working.
BRAD: Mm-hmm.
PIPPIN: But then the first time it caught a bug for me that we completely missed, I realized the value of it because it’s going to go and do more tests and different tests than you’re going to do every time.
BRAD: Yeah.
PIPPIN: This morning, for example, I committed a fix or two to some of the calculations for discount codes on purchases. Now, the test that I ran showed me that everything was running, like my personal test. I’m going through the checkout process to see if everything works right. I’m redeeming the discount code. I’m completing the purchase. All of those tests worked.
But then all of our unit tests that I ran in the background tested it in another five or ten different ways. Not necessarily in different ways, but with different dollar amounts. I mean sometimes a $10 purchase will work perfectly, but a $5 purchase will be a little different.
For example, this morning we were working with flat rate discount codes, and we have a bug in EDD, and it’s a known bug that we’re going to try and fix at some point. But it only presents itself when you have an odd number of items in the cart and an odd dollar purchase amount, and you have a flat rate discount code. So if we’re going through a test and we’re making a $10 purchase with one item, everything works great. If we’re going through with a $33 purchase and 5 items, it fails. In this particular, a calculation just gets off by $0.01 or $0.02. That’s an example where, if we had a unit test in there to go and say, okay, let’s calculate this on 15 or 20 different dollar cent values, we’d be able to catch that.
BRAD: Right.
PIPPIN: In this case, we only caught it because a user just happened to have the right variation in their cart to notice it.
BRAD: Hmm. Interesting. I wonder. I’m wondering. I’m thinking about this keeping unit tests up to date problem. I’m just thinking maybe we should start writing our tests first before the code.
PIPPIN: I’ve seen a lot of people do that.
BRAD: Yeah?
PIPPIN: I think it’s called test driven development.
BRAD: Yeah, TDD.
PIPPIN: TDD.
BRAD: Yeah.
PIPPIN: Yeah.
BRAD: Well, I thought that was just — is that what that means to flip it over?
PIPPIN: I think so, yeah.
BRAD: Okay.
PIPPIN: Say, basically, we’re going to write our test and then we’re going to write the code for it. I could be wrong on that, but I think it is.
BRAD: Okay. I thought TDD just meant you have unit testing in place.
PIPPIN: It might be.
BRAD: But anyway.
PIPPIN: If somebody wants to correct us on that, feel free.
BRAD: Yeah. Who’s right? Is it Pippin, or is it Brad? Vote now.
PIPPIN: It’ll be a challenge.
BRAD: Probably Pippin. My money is on Pippin.
PIPPIN: I do find myself actually using that process in my development sometimes, not so much where I’ll write a test for my code before I write the code, but I will write it in such a way, like, I’ll write my function to return the value or return it in the way I know I want it or I need it, and then I’ll write the logic inside of the function.
BRAD: Hmm.
PIPPIN: I find that that helps me out because it’s basically saying, okay; we have our starting point, which is the function. We know our endpoint is this return value. Now let’s write the logic that gets us from point A to point B.
BRAD: Right. I wonder if another problem with keeping unit tests up to date is, say you modify a function, right? And you change its output, but you’re not updating your unit tests to test for the new types of output. That could be a problem too, right?
PIPPIN: Absolutely.
BRAD: That would probably be an easier thing to miss because, with a new function you know, oh, it’s a new function and it doesn’t have a unit test. It’s pretty obvious when you look at the commit, right?
PIPPIN: Yep. How do you keep track of those? How do you not miss those? How do you keep up to date? I know there are some automated tools. Is there one that you use?
BRAD: No, I just thought of this right now. I mean, we’re really early on in our unit testing.
PIPPIN: Well, I know, and I know that you’re using this because of from our pre-show discussion, but I think one of the ways that you can help catch that is getting an automated unit test system built into your workflow.
BRAD: Yeah.
PIPPIN: Out of the box, most unit test suites require that you go run the command. Like with PHP Unit, you’re going to go to terminal, and you’re going to type PHP Unit, and it’s going to run your unit test. But one thing that you can do that helps you keep, not necessary keep your tests updated, but keep, maintain a passing build is to have tests that run on every single commit. Every time you commit a change to GitHub or BitBucket or whatever version control system you use, it triggers the unit test to run. Travis-CI is a really awesome tool for that. Every time you commit to your repository, it goes and triggers the unit test, which means that if you go and change a function and that breaks the unit test, but you don’t run the test yourself, it’s going to catch it for you once the test completes after you’ve pushed it to GitHub.
BRAD: Yeah.
PIPPIN: And that’s really valuable. It caught a bug for us last night. Last night, I committed a fix, and I was slacking. I didn’t create an issue on GitHub or do my due diligence in recording what I was changing. I just committed it directly, which was an error on my part, but I committed it. It was kind of one of those cowboy coding moments where I didn’t test it. I just committed and said this is done.
BRAD: Oh, you careless son of a —
PIPPIN: I know. I know. I know. But this morning I saw a commit come in from Chris and he says the error from the build failing was driving me nuts, so I fixed it, and it turns out that I had committed a typo and it actually broke the unit test.
BRAD: Oh, nice.
PIPPIN: The test didn’t work anymore. But I wouldn’t have caught that if our automated testing didn’t run ten minutes after I committed that change because I committed it, and I went to bed.
BRAD: Right. No, I agree. Automated testing is awesome. I don’t think that will help though in the scenario I was just describing where you change a function and you forget to update the unit test. Your test might still pass, right? But it’s not testing the new scenarios that you’ve added to the function. That’s what I meant.
PIPPIN: Sure.
BRAD: Do you know what I mean?
PIPPIN: In that case you just need to continue to update your function, I mean your test, to make sure that they’re thorough.
BRAD: Thorough and cover the entire function instead of just a subset of the function. Yeah.
PIPPIN: I think that’s also a good case where, if you need to write a whole bunch of different assertions for your test in order to cover all the possibilities for the function, your function is probably too complex.
BRAD: Yeah, that’s true. We’ve got a few of those in our code base.
PIPPIN: Oh, oh, I think everybody does. Anybody who has an advanced code base is going to run into those eventually. I mean, we have functions that are like 400 lines long, and I think this should not be this way.
BRAD: Yeah.
PIPPIN: But it’s a nightmare to go and change it.
BRAD: Yeah.
PIPPIN: I think a tip that really, really helps people that are getting into unit tests and wrapping their head around it is, when you’re writing, to write testable code, keep your functions as simple and one or single task functions.
BRAD: Mm-hmm.
PIPPIN: A function should do one thing and no more.
BRAD: Yeah, because your test functions, it becomes really difficult to write the names, to think of a name for your test function, right?
PIPPIN: Oh, no, it’s easy.
BRAD: Well, I mean if you have a 400 —
PIPPIN: That’s actually a function name.
BRAD: [Laughter] I know, but if you had a 400-line function that does a bunch of a different things, then it becomes impossible to choose a name for your test functions, right, because they do so many different things. It’d be ridiculously long, right? But, yeah, Travis-CI, that’s the thing that made me realize, wow, unit testing is so powerful because one of the things that it does as well is it sets up different environments, so it’ll test PHP 5.3, maybe even 5.2. I’m not sure.
PIPPIN: I think you can go back to 5.2.
BRAD: Yeah, I think we do 5.2, 5.3, 5.4, 5.5, and now 5.6, so 5.6 down to 5.2, and so it’ll catch things that have changed in PHP. If you’re using a function, for example, we recently used parse_string function, and we used it in such a way that it wasn’t supported in older versions of PHP, and the unit test caught it. That was pretty awesome, right? Those are the kinds of things that you’re not even going to catch if you’re running your unit testing locally, right?
PIPPIN: Nope.
BRAD: Because you’re probably just running it against 5.4, 5.5, or whatever you have installed locally.
PIPPIN: In Travis-CI, do you also test against different WordPress versions?
BRAD: No, we do not at the moment. Do you?
PIPPIN: That’s another one that I would recommend setting up. For EDD, for example, we test Trunk 3.8. No, we do Trunk in 3.8, which I guess we should also have 3.9 in there. We just haven’t updated our config. Then we also test it with multisite on and multisite off.
BRAD: Oh, yeah, we do. We definitely do that. I remember.
PIPPIN: Right now we have eight different environments that it runs in.
BRAD: Oh, really? Huh. Oh, yeah. Sorry.
PIPPIN: We’re doing 5.3 to 5.4.
BRAD: Yeah.
PIPPIN: And then we’re doing multisite on, multisite off, for Trunk, and 3.8.
BRAD: We have 16. We’ve got — we use Latest. I’m guessing that’s Trunk, and 3.9 right now, and multisite on and multisite off, and then all the PHP versions, so those 3 combinations end up giving us 16 build environments.
PIPPIN: I’m going to actually, since I’m thinking about it, need to go in and update it to do 3.9 and 4.0 as well. But it’s definitely having those other, have those tests run in all those different environments is just really a nice — it helps you sleep at night.
BRAD: Yeah.
PIPPIN: To be honest.
BRAD: Yeah. I mean it just brings unit testing to next level, right, because you can’t. I mean it’s not feasible for you to do that locally, right? I mean you could cook your own system where you’re spinning up vagrant machines or something and then run the unit tests on them. I’m sure there’s something out there, some kind of framework that does that. But if you’re willing to spend a little money, Travis-CI is the way to go. Actually, if you’re an open source project, I guess EDD wouldn’t actually cost anything, right? Travis would be free.
PIPPIN: (Indiscernible)
BRAD: Yeah. Anyone that’s open source is free.
PIPPIN: Yeah, it’s absolutely worth it. If you’re not — if you’re just getting into unit test or you’re already well accustomed to unit test, Travis-CI is absolutely worth it. Getting your plugins written with unit tests, even if you write a small plugin, I think unit tests are really, really valuable because it really makes you think about your code in a different way. When you’re writing code it’s really easy to be just be like, yep, that works, but not think about whether it works in a smart manner. PHP Unit or unit testing makes you think about is this function actually working the way that it should, or is it intelligent to have this function doing five different things? Well, try to write a unit test on it. The answer is probably going to be no.
BRAD: Hmm.
PIPPIN: All right, so if anyone else, if you have any questions about unit tests–we’re going to have things in the show notes for tutorial series and things to go further, get you started in unit test–don’t hesitate to ask. Unit tests can be super complex. They can be easy to get started, but then once you really get into them, there are so many different things that can come up. If you have any questions, don’t hesitate to ask.
I think one thing that we want to talk briefly about before we get closer to wrapping things up is WordCamp San Francisco is coming up. I believe it’s this weekend. I am kind of disappointed I will not be there this year. This is the first year that I haven’t been there in a couple years. But if you’re going, it’s an excellent event. Brad, you’re not going this year, correct?
BRAD: I will not be going because I will be here helping my wife with our six-month-old baby.
PIPPIN: It’s a pretty good reason to stay home. That’s pretty much the same reason that I’m staying home.
BRAD: Exactly. Exactly. I’ll be heading out for conferences again in the spring once things settle down around here, but for now.
PIPPIN: Yeah, well, if anyone is going, I know along with the normal WordCamp San Francisco, the Community Summit is out there this year, which is a little different than it was a few years ago in that this one is actually open to the public. I think you had to get tickets for it, but it’s there, so there’ll be some cool discussions about WordPress Core, plugins, themes, et cetera, going on there. Anything else that you want to throw in, Brad?
BRAD: No, I think that’s just about it. Check us out on iTunes and drop us a five star if you like the show.
PIPPIN: Yeah.
BRAD: That’d be cool.
PIPPIN: Go check out our permanent sponsors as well. The guys from WP Ninjas are really awesome. They’re doing some really great work: Ninja Forms and Ninja Demo, as well as some other plugins. You can check them out at WPNinjas.com.
BRAD: Awesome. Thanks, everybody.
PIPPIN: Thank you.
Leave a Reply