 My name's Karl Alexander. I'm also a work camp organizer for work camp Montreal. I've been organizing work camps and wordpress events since 2010 I think And I also write regular on my blog, which I will talk about just shortly If you want to talk to me the easiest way to do it is on Twitter my handle is twig press and like I said, I write regularly on my blog Karl Alexander dot CA before we begin This is a really common joke around me if you've ever read anything on my blog I like talking about advanced topics. This kind of happens pretty often when I get to speak But I fight very hard against this and this talk is no exception. There's a lot of extra material around this talk There's a github project which I'll point at the end and there's also a 3000-word companion article that you can refer to so if I normally I do a lot of question periods during the talk But if I lose you during there's at least that that you can refer to later on So now that this is done. Here's what you're all here for This co-work the other day who's had this problem before It's it's a really frustrating problem and the you want to protect yourself and the only way to the only way to do that is with unit testing and What is unit testing? It's testing at the smallest scale It's in putting values into a function and checking what comes out at the end And the goal with that is to have a constant behavior from your code It's also to have a sort of safety net so that these frustrating moments of god damn it This work. Yes yesterday. I don't understand and Because of that your code also becomes a lot stronger and you get higher quality code out of it so Let's talk a bit about unit testing before getting it to an example the most important part of it about unit testing is Isolation It's actually the cornerstone of unit testing. It's done using test doubles Um test doubles are these kind of machines I call them magical machines that surround your code and gives you absolute control like if you were some sort of god and And what it does is it lets you know? What is my code doing and? This is important because it's not really about what is wordpress doing and I'm gonna do a small tangent about that to talk about unit test versus The wordpress test suite The wordpress test suite is what really we call integration testing and integration testing has a kind of different relationship with isolation It's it's more about how we piece code together It's your plug-in with wordpress. How does it behave together? It's not so much about This idea of isolating a piece of code where like the term unit comes from and it's not really that One is better than the other Ideally you should do both So now that I've done this little tangent. We're gonna start talking about How you can get started with unit testing? So for this for this example, we're gonna be focused on Unix based Operating system, so I'm really sorry for Windows users out there If you want to do this you can use a virtual machine But really a lot of the tools are just based for macOS or Linux In terms of the code, we're gonna be a bit further ahead. We're gonna use PHP 5.3 for the code and 5.4 For the tests the reason for a 5.3 is we're gonna use namespaces and the reason for 5.4 is the testing one of the testing libraries that we're gonna use use as traits so Because of that we have to go with PHP 5.4 We also need composer PHP unit, which is the default Testing library that's also what WordPress uses to run its test. So we'll be using that as well and We'll be using WPCLI our favorite WordPress command line client This is a bit optional, but it does speed up a bit of the process of doing this Creating our first unit tested plugin so This is the easiest step so far Just use WPCLI and scaffold plugin and because you have WPCLI scaffolds already all the unit testing Boost trapping files. It simplifies a lot of the work. That's why it's an optional dependency for our example But it does really simplify a lot of the work that you want to do so it's really useful for that We're also going to add a composer.json file. That's for Composer, which is our package manager that we're going to be using for a testing setup and Inside it we're gonna this is just a sample of what it looks like really the two important lines are this one which basically says that we're gonna use PHP 5.3 and This one which required dev is basically a second section that says we need this library when we're developing So it really has no impact when you're creating your plug-in or Coding in general when you're sending it to clients is just for our testing purposes when you're gonna send it on github for Automated testing it just will download this library to run our tests We also have to modify the bootstrap PHP. This is this is a file created by WPCLI It looks like this and the only thing that's missing is the composer Autoloader So we're just gonna add that line here at the top and we're good to go so what we're gonna do is we're gonna create our first plug-in function It's a pretty easy function. Let's just get a plug-in get your plug-in option With our namespace and our function where we namespace our option because everybody knows that you should namespace your options So we're gonna be testing that to make sure that our plug-in correctly namespaces options when It fetches them from the WordPress database So our first unit test This is that this is what the unit test looks like right now As you might have noticed we're still using the same namespace as before unit test demo We're also gonna import PHP mock which is our mocking function mocking library for PHP functions, which I'll go over in a bit and Then we have our demo demo class Demo test class, which is where we'll store our tests and our trait, which is the what we were using from the PHP mock library That's why we need PHP 5.4. It's just because of this one single line I I want to note that if you do not want to use this library Tenup does have a library called wp mock that's a bit more limited, but does not have this PHP 4 requirement So if you want to use that instead You can use that as well to do something like this So testing our demo get option Here's our test here's our testing function so right now What we have is test that demo get option. We always have to pre-fix our Functions with test underscore. This is a requirement from PHP unit That's how it flags this function as a test versus some upper function that you have within your class and Then we have this asserts equal So so far we haven't talked about assertions assertions is is really the heart of a unit test it checks that What we're getting back from our function is what we expect To get back. So in this case, we're gonna test that We expect to get back the value bar when we do demo get option For the foo option Now what what happens if we try to run this? Damn doesn't work That's because right now it goes to the WordPress database And the WordPress database isn't preceded with any sort of option So it returns false. So this is not what we want. So we need to fix that We need our test double. So this is why we needed the PHP mock library. So This is we're gonna create a mock of get option So what's a mock? A mock is a test double A test double is of not a method With unit testing where you can simulate the function or an object and verify how you interact with it this is really important because It's the only type of test double that does that and it's really at the heart of what we're trying to do with unit testing is we want to check the behavior of Get option true our demo get option Method so what we're gonna do is we're gonna configure our mock So the first thing that we're gonna do is we're gonna say I expect get option to get called once And then we're gonna say I expect that I Expect get option to get called with the parameter demo underscore foo and when it does Satisfy both those criteria's it will return the value bar And then if you try to run our test again, it passes because at this point we've managed to simulate We've inserted our mock instead of the regular WordPress function and at this point we're not hitting the database anymore. So we're not getting the value false anymore, which is really Powerful and it's awesome because our first test passes and we can try to do something a bit more complex now with it another common thing that you see when you use get option is you store arrays in it and One of the things that you run into is that you don't always get an array back And the common way that if that you solve that in core is you'll just cast That option as a as an array right away Just in case that You don't get the value that you want or or not an array, but what we're gonna do this time is we're gonna do We're gonna have our function do that for us But we're gonna do it in reverse We're gonna start with the test failing and we're gonna We're gonna go through that and make a pass it We're gonna fix our code and make sure that our test pass And that's gonna give you a bit of an idea of what test-driven development is which is this philosophy of Going with your tests written first and then writing your code afterwards with us the idea of Writing in the least amount of code possible to fix your bug, which is the failing test So before we do that we're gonna have to do a small change to our demo get option Method we're not and we're gonna need to pass it a default variable So what we're gonna so we're gonna update our demo get option Function and add the default value, which is no, but we also need to update our tests as well So now we're saying not only are we expecting? Demo underscore foo, but we're also expecting the identical value now And you'll notice here that we're using equal and identical to This is just from PHP so in PHP you have double equal For equal to and then triple equal signs for identical This prevents issues for example if you pass an empty array or an empty string Those are all going to be equal to the same thing With a double equal, but they won't be equal to the same thing if you use a triple equals So that's why you use identical to So let's create our failing tests So this is this is our our failing tests so far it's really similar to our other tests really because The idea with unit testing is you're changing your inputs outputs and expected values So there shouldn't be too much to change between tests and this is the same case here What we're saying is we're saying that We want to pass the value the default value to be an array And we expect to return bar again because that's the error that we're checking for but on the other side We expect the value to be an array with bar inside and If you run your test right now it's gonna fail Because we haven't changed anything in our code and we're still gonna return bar and not an array But we can do that we can fix that really easily By adding this line here which checks if our default value is an array But the option that we got back is an array we cast that option as an array and return it and then and at that point our test passes and That's it for like this simple example, but the idea with unit testing is it's in a habit By itself it feels pretty insignificant like I'm pretty sure you were thinking you saw these two examples. You're like, well, that's pretty basic That doesn't do that much But really what it is is it's really one loop in your safety net it takes Hundreds of these tests for really for it to to feel significant to feel safe because one test by itself is just Again a small case a small unit of code that you're testing, but we're pressed or your plug-in is hundreds of functions and each of them have special cases that you can think of every day But you might not be thinking about in eight months when something breaks and you don't remember why it broke well, it's really hard to go back in those cases and It might take you a day to figure it out where where you did that little typo and how it interacted with everything else in your code so it's a lot easier when you can have these mocks around it and I've went already ahead for that one But it's a lot like picking up and you have it so my suggestion is you have to start and you try to do it a bit and you keep doing more and more and Like any exercise you it's hard to stay motivated, but you keep at it and that's it so the first link is The demo project so this is on github if you want to see The exact code that I run right now. It also also runs through Travis CI So if you want to see how this runs with an automated Testing system like Travis you can see how that works. So and then below is the article I wrote on this Thank you questions. All right. Thank you. Okay I Do it So that's it's a great primer like oh you're getting into it. I have a brand new project here some like tests. Mm-hmm What if I'm a developer. I have a bunch of plugins I've written hundreds of plugins. Yeah, how do I get started with projects? Like I already have like where's the best place to start in terms of developing those well There's a there's entire books written about this, but the best strategy that I can give you is Because it's small functions You can even go like if a client comes to you and creates a Tells you oh, this isn't working and then you create an issue in your ticket system You can be well from this point on whenever a client Has an issue and we find a bug in the code we have to create a test for that piece of code and then you just start from there and honestly It you can get pretty far with that just that simple philosophy of just going from that point on and creating a test around it and the beauty of unit testing in that scenario is that you don't have to Create all this infrastructure around WordPress like most of the WordPress tests You have to see the database create your options inside with this you just create a small mock You're like oh, this is this is what's happening like it's happened so many times How many people hear bar dump when something goes wrong? Yeah, exactly So this is the mock is really similar to a bar dump in the sense that you you've bar dump and you see what the values are and You're like oh, this isn't working You can you can just simulate that through the mock because you pass the same values through it and You'll see that the code isn't working and then you can fiddle around with it till it works So it's really powerful around that and it lets you solve these problems a lot faster especially for your clients because again, there's a bit less setup required but The best system is really to just start with the bugs like as they come in Like when I was at an old agency, that's what we did We just started at that point and at that point we said from this point on We and there's no more chips coming into this house And you basically start doing a test every time there's a bug and you'll be surprised how far you can get with that Thank you. Any other questions? Hello. Hello. Hey, so I have a few questions about milliseconds. How many how fast has Your test suite been running for plug-ins I'm running about 200 right now and They run in two seconds It really it will depend so in this example I took some shortcuts for example WordPress is still loading If you if you paid attention because I'm still bootstrapping the same way WordPress is loading When it doesn't really need to the idea is you're supposed to Decouple WordPress entirely from from the the testing And that's supposed to that speeds it up a lot because you're not doing an SQL collection like To give you an idea for the get option if you were doing a WordPress test normally each option test is a it's a database connection Which is incredibly Slow Because you connect to the database get the data back And you have to re-establish that connection for every test unless you you specifically Configure your suite to keep the connection live, but that can be very costly in terms of time and that's why into unit tests in general are supposed to be faster than integration tests which are supposed to be faster than acceptance testing which I haven't talked about but is Is it's all at the browser level? You had another question. Yes, so for your so for your automated testing do you test between them? Multiple matrix matrices of WordPress multi-site installation The press running under a subdirectory WordPress. Well, I actually you you don't need to do any of that at least Not for unit testing because again, you're mocking The WordPress functions so as far as as your concern WordPress Isn't really there You're you have to be okay. I expect to get this value back from WordPress It's on your own as to do that step You have to be able to say okay Well like in this case I expect to get bar back But really in most cases if you're smart and you saved your value as an array you're you're not gonna get that So you're really testing hypotheticals in that scenario So you really don't need to run through the entire Matricy what you do need to run through though is all the matrices of PHP versions because you're testing code So in that respect you still need to run that but in terms of of the WordPress version You don't need to unless you're testing again Changes like one test that that would come to mind right now is I've I ran into a lot of issues recently There was a WP sign up the emails parameters changed a lot So for example for that you want to run a bunch of tests, but again, it's on you to simulate that You don't need WordPress to be different. You just have to be like, okay. I I need to set up I need to send these variables if WordPress is lesser than this version which you can simulate yourself So again, you you really want to get WordPress out of the picture, but In terms of timing like I said before we're still loading it that's because One of the hurdles that I haven't been able to get over yet is there's some classes like WP error or underscore underscore For the translations that are really hard to Extract out so if you have like translations in your in your code it can be hard to Deal around that so it's just kind of a cheat to to leave it there So that the fall back to WordPress still works because it's just a namespace cascading. That's how it works What's your approach on testing WordPress themes and how have you gone about that? I've not done this for teams, but in terms of just thinking about it right now I would approach it the similar way in the same in the sense that you want to just test your functions that PHP You're not really testing Your JavaScript like if you want to test your JavaScript in unit testing you have to use a different testing suite But if you're testing for example, if if a hook gets added at the right time the for example the 10 up WP mock has a really good Set of functions around that like it says like I expect this action to be To be entered or I expect it not to be entered and then you'll get an error if that happens So you can definitely do that with your teams but I think it won't be as strong unless you have a lot of business logic in your team because Unit testing is really about the logic of your code as more so than the behavior of your team for Your users or clients Last question would have you been using the WP test suite classes that they provide for Providing shortcuts for testing work like WordPress URLs and navigation and the rewrite rules like have you been using the help or libraries in the test suite? Yes, but not in this context Because again the context that I'm trying to like when I'm so It's a bit unclear without doing a separate talk on tip like the global scope of testing But what we really want to test with unit test is really Am I insane not really is WordPress insane? So it's really no, but it's really it's really about your code It's about what you're coding and your business logic as opposed to what WordPress is doing and in those cases The WordPress helper functions are super useful to know is is what I coded playing well with WordPress That's super good. But if if you're trying to test like If my plugin is activated at these rewrite rules You you don't need you don't need those helper functions to figure that out and it'll be faster Like you said like you want if you want your test suite to run really quickly, it'll be a lot faster if you do that Yeah, those would be useful for integration test, but you're right. That would be separate from the unit test suite Yeah, yeah, like I said initially like I I've actually zero problems with the WordPress test suite It's just depending on what I'm trying to do Sometimes I'm just trying to see if the way I'm coding things makes sense And not really I'm not I don't want to be bogged down by how it's integrating into WordPress like I'm really more focused on on the behavior of my own code and in that that sense I find that unit testing is extremely powerful, but you have to use it It's not an absolute solution it you have to find where it fits in your own workflow and Really on the complexity of your code right like the same the example here was quite simple, but a good example is like You know if you're WooCommerce and you have a complex taxation that you Like add-on and you want to test the business logic around there Then it's a lot more interesting for that because really it doesn't necessarily have anything to do with With WordPress itself. You're just trying to test the taxation logic Thank you. Thank you Any other questions? All right. Well, thanks a lot