Testing Jargon Overview 0:00There's no two ways about it. Jargon in the testing world is a little bit insane. And by insane, I mean incredibly overwhelming. There's dozens and dozens and dozens and dozens of terms just to get you through the front door. And then the worst part is, people from community to community disagree on what these terms refer to. So, as someone who's just trying to find a way to better test and drive their projects, this ends up being a massive hurdle. So, in this series, we're just going to focus on one topic at a time. What is a unit test? What is a mock? What is a stub? And then hopefully, when things get a little blurry as you get into this stuff, you can just watch the related lesson to brush up. Okay, to start, we'll go with unit test. Now, I will be using a test framework called PHPSpec here, but I don't expect you to know how to use it. If you're familiar with it, great. If you're not, that's okay. We're focused a little bit less on the code Defining Unit Tests 0:51using a test framework called PHPSpec here, but I don't expect you to know how to use it. If you're familiar with it, great. If you're not, that's okay. We're focused a little bit less on the code in this series and more on what the actual term represents. Okay, so what is a unit test? And let's break it down. We don't need to make this any more complicated than it needs to be. So, here's how I think of it. A unit test gives us a very simple, very fast way to test a small piece of functionality. And really, that's all there is to it. Now, when I say small piece of functionality, that could be making sure that this method does what I expect. So, when I call this method with that argument, in response, what do I expect to get? That would be a unit test. Now, as a basic rule of thumb, you want these tests to focus on one thing at a time, and you don't want them to really be talking to collaborators too much. When you write a unit test, you probably don't want it touching the Tag Parser Example 1:44you want these tests to focus on one thing at a time, and you don't want them to really be talking to collaborators too much. When you write a unit test, you probably don't want it touching the database. You don't want to be making some kind of API request to a third-party service. All of that is separate from what you're really trying to test. All of that stuff is separate from what you're really trying to test here. Remember, we're testing at a very low level here. So, for example, if I call this method but I don't give it the correct argument, then I expect that exception to be thrown. That would be its own unit test. All right, let's work through a very simple unit test together. Maybe you're building a CMS, and when the user creates a post, you want to offer a little text area so that they can enter a comma-separated list of tags. And then behind the scenes, you will parse that list, turn it into an array, and then save all of those to the database or something.area so that they can enter a comma-separated list of tags. And then behind the scenes, you will parse that list, turn it into an array, and then save all of those to the database or something. So, that means at some point, we need to have a method or a class that handles the process of parsing that string of tags. So, let's write some unit tests to drive that entire process. phpSpec, and I'm going to describe this parser. It will be Acme. I'll keep it in a parsers folder, and I will call it tagParser. Okay, I'm going to run my tests here, and it's going to offer to create the official class for me. Nice. I'm also going to set up an alias here so I don't have to write this over and over. Okay, and I'm at green. So, now you'll see that here's my test, and we just have one test to get us going. Now, within here, I'm going to describe what the code should do. So, for example, when I call a parse method on this class, how should it behave? If I give ithave one test to get us going. Now, within here, I'm going to describe what the code should do. So, for example, when I call a parse method on this class, how should it behave? If I give it this, what do I expect in response? It parses a comma-separated list of tags into an array. Notice how we're being very specific about what it does. This is a good thing. It forces you to actually think about what this code should actually do versus what some people do, which is something like testParse. Well, that's not very useful, is it? Write it out. Don't be lazy. All right, so in PHP spec, when I use this, this would actually reference the tagParser class. So, when I call this parse, think of that as a way of saying, when I call the parse method on a tagParser class, what do I expect to happen? Okay, so we call it, and we'll give it some tags, foo, bar, bass. Now, once it's done parsing, what should it return to me? Well, that should returnon a tagParser class, what do I expect to happen? Okay, so we call it, and we'll give it some tags, foo, bar, bass. Now, once it's done parsing, what should it return to me? Well, that should return an array of foo, bar, and bass. So, in this case, not only are we writing a unit test, but we are using test-driven development to drive the design of the ultimate class here. So, let's try it out. We run it again, and it's going to let me know, hey, you don't have a parse method. Do you want me to create it? Yes. Let's do it again, and now we can see we expected that array, but of course, null was returned. So, that's our next step. I'm going to switch over to tagParser, and let's get going. So, when I give it a string of tags, I need to parse that. Return, explode, I will use a comma as a separator to search for, and then I will pass it the string of tags. Okay, let's run it, and we get green. So, now, for the lifetime of our fictional project, we never have to manually Handling Spaces in Tags 5:22as a separator to search for, and then I will pass it the string of tags. Okay, let's run it, and we get green. So, now, for the lifetime of our fictional project, we never have to manually verify if this class does its job correctly. Now, though, everything's working, but imagine that once we push this up, and real human beings begin using this, we realize that, like normal people, they put a space after their commas. Well, now, if we were to run it, everything's going to fail, and that's because, of course, in this case now, some of our items will be space and then the word, like so. So, we need to strip that out as well. Okay, well, now we have a new test, so let's go ahead and fix that. In this case, I'm going to use preg split so that I can reference a regular expression, and then I'll say look for a space but it's not required, then a comma, and then another space that's not required. Okay, we run it, and now it works. But now, further, Adding Pipe Separator Test 6:16a regular expression, and then I'll say look for a space but it's not required, then a comma, and then another space that's not required. Okay, we run it, and now it works. But now, further, what if down the road we find that people also like to use pipes to separate them? Okay, well, if we want to support that as well, we can do so. Now, we could duplicate this, but just be a little bit careful of that. You don't want to end up in a situation where you have one test and then just a bunch of assertions one after the other. That makes things a little tricky. So, instead, why don't we write a new test here? And this way, we can further describe the behavior of the tag parser. It allows for a pipe separator. Also notice that when we write our tests in this way, it actually makes for really good documentation. If I'm new to the system and I want to learn more about how this works, well, I can just look at the tests and I can read perfect descriptions of whatit actually makes for really good documentation. If I'm new to the system and I want to learn more about how this works, well, I can just look at the tests and I can read perfect descriptions of what it does, and then I can review code samples right below it. Very helpful. So, in this case, we're going to duplicate this, and we're just going to say if we use a pipe as a separator, everything should still work just like it did before. All right, we run it, it fails, so now we make it pass. In this case, we're going to look for a comma or a pipe. We'll be fine. And if I run it again, we're back to green. All right, so that's been your crash course on what a unit test is. The important thing here is the entire time we were focused on just a small piece or unit of functionality. We weren't touching a database or querying an API or referencing a bunch of collaborators. We were exclusively focused on one unit of functionality. In this case, we have it Unit Test Recap 8:00of functionality. We weren't touching a database or querying an API or referencing a bunch of collaborators. We were exclusively focused on one unit of functionality. In this case, we have it as simple as can be. When I call the method, I expect it to return to me that data. Let's write a test to make sure that works. But in other situations, you might be touching a closely related collaborator. That's okay. Or maybe you call a method and it changes some state on the object and you want to make sure that that state was changed correctly. That would be another case for a unit test. So at no point are we going from the outside in. We're not thinking, when I go to this page and I fill out this form, then this should happen. That's a completely different kind of test. So in closing, when you think of a unit test, just think of a small piece of functionality.of test. So in closing, when you think of a unit test, just think of a small piece of functionality.