 Welcome everybody to Confidently Testing Word Press. If you didn't hear me ramble on this morning, my name is Steve Crenwell. I'm at Steve Crenwell on all the social networks that matter. And if you're the kind of person who likes to have your own copy of the slides to follow along, you can grab them now at stevecrenwell.com slash slide slash testing wordpress. They're also very, very, very small in the bottom of each and every slide. If you don't grab them now, though, don't worry, I will tweet them out later. Let's talk about testing fundamentals, shall we? Before we can really understand how to test well, it helps to understand the role that automated testing plays in software development. Through automated testing, we're able to codify exact testing procedures. This is going to reduce the amount of time it takes to run A, because we don't have someone manually sitting there going like, let me run through every test scenario. But B, it's reducing that chance of human error because no one can forget a step because computers never forget. Tests also become very easily reproducible because they're scripted. It's not someone's doing something in a different way or in a different order. Everybody is running the same tests. It doesn't matter if it's your CI pipeline or if it's a developer on your team. Automated testing is also very important if you want to reach that holy grail of continuous integration and continuous delivery. Obviously we don't want to be deploying to production over and over and over if we don't actually know that it's going to work, because that causes a lot of lost weekends, a lot of frustration, and a lot of drinking. There are a few different types of tests. At the base, we have what's known as the unit test. This is going to test the smallest possible unit of our code. Often this is a single function or a single class method. Moving up, we get to the integration testing. Sometimes this is also called feature testing. This takes all of these individual components that we've already tested with our unit tests and tests how they all kind of come together, how they integrate. Above that, we have end to end, sometimes known as full stack testing. And this typically is going to test the full path through an application. As a user, I arrive on this page, I click this format, I put it, I provide this data, I click this button, and I expect this to happen. We're going to consider end to end testing beyond the scope of this talk. We're going to focus on these first two, unit and integration tests. Now when we take these types of tests, they're often arranged in what's known as the automation test pyramid. Along the x-axis here, we have the number of tests. So the wider the base of this pyramid, the more of those tests we should have. As we go up the y-axis, we get the cost. This isn't just cost in dollars, but cost in time, cost in effort, how difficult or how involved are these tests to write. At our base, ideally we're going to have the majority of our tests be unit tests. We want to test the individual functions, make sure that things behave the way we want them to. Moving up, we get to integration tests. A little more involved to write. You might have HTTP requests going on. You might be changing session state, anything like that. But still generally pretty easy, pretty quick to run. Up at the top of the pyramid, we have our end-to-end tests. These are going to be more expensive to run because you're often doing something with a headless browser. You need to spin up Headless Chrome and visit this page and click this and fill this out. They're going to be more involved to write. They're going to take longer to run. They're going to be really good for testing happy paths. The user must be able to sign up for our app because if they can't do that, we don't make any money. Those are important cases to have end-to-end tests. Another concept that's worth understanding is what's known as the system under test. SUT, or SUIT, I don't know, I live online. We don't really pronounce things. But that refers to the system that we're currently testing. If we're writing a unit test, we might be testing a single method. The system under test is that method. We're actually testing a class in an integration test. That class is the system under test. We want to make sure that we're isolating what we're trying to test. And for anything else, we want to use test doubles, which we'll talk more about in a moment. So we've talked about unit tests and integration tests. Well, WordPress comes along, and like WordPress does, it makes things a little more difficult sometimes. WordPress, by its nature, is a very tightly coupled system. Different parts of WordPress are going to rely very strongly on one another. You have a lot of global variables, for instance, that are holding state. So it's hard to say, I want to test this one function when this one function has like 18 side effects that you also need to account for. Really, WordPress is... it makes it difficult to test anything in true isolation. It's admittedly a teenage dapplication because, well, that's what happens when you've been around for between 13 and 18 years. That's literally a teenage dapplication. It's still definitely workable, and we can still test in WordPress, but it does require a bit of creative thinking. If you've done any software testing in, quote, unquote, pure frameworks or more modern frameworks, you might kind of be like, well, everything has its definite place. WordPress, we muddy those lines a little bit. But let me show you what we're going to be working with today. So this is our testing toolbox. At the core of everything, it all comes down to PHP unit. PHP unit, if you haven't worked with it before, is the most popular test framework slash runner within the PHP ecosystem. There are a few other alternatives, but PHP unit is kind of by and far the one that everybody goes to. It's also really extendable by other frameworks and applications, and you can write add-ons for it and everything. And it also serves as the basis for the WordPress core test suite. The structure within PHP unit, we have a few levels to be aware of. At the top, we're going to have one or more test suites. A test suite is a collection of test classes, and it's usually you might have, like, a unit and an integration test suite, or you might have a front end and an API test suite. The next level down, we get the test class. These are literally PHP classes, which are collections of test cases. Now, these will often be centered around a particular feature or a model. You might have a user test. You might have a post-test, something like that. And within our test class, they're comprised of test methods, which are literally PHP methods, functions within a class. These are going to then, in turn, contain one or more assertions, and you can think of each test method as a scenario that you're trying to test. Now, when I say assertions, basically that's where, in our tests, we ask a question, do things work the way we expect? We make an assertion against what's happening. PHP unit is going to come with a ton of default assertions, and, like I said, it's easily extended by other frameworks or applications. So let's take a look at some of the most common assertions you'll be using in your tests. First of all, we have the question of true or false. And as we go through these, you'll see that everything really boils down to true or false. So assert true is going to do a strict comparison to the Boolean true. Conversely, we have assert false, which is going to do a strict comparison to false. We can check for equality. Things like assert equals, which is going to do a loose comparison. Note the double equals as opposed to the triple. We can do assert same, which is going to do a strict between two values. Something to be aware of here, if you are comparing two instances of the same class, so two objects that are not the same object, but the same class, they will not be considered equal. So something to be aware of. You can verify contents. So you might do something like assert contains. We have a string foobarb as, and we want to see if bar is in it. Well, yes, bar is right there in the middle. And we pass it an array. It's aware how types work. So we're looking for a value of B and look right in the middle of this array, ABC. We can use regular expressions. Any regular expressions fans in the room? Okay, I'm not the only one. That's great, because I'm like, regex guy and most people are like, what are you doing? Why would you do that? And it's just the regex people laughing at that. Like, yeah, I've been there. Most every assertion is also going to have an opposite and equal assertion. Equal and opposite flows much better, but no, let's mess that up. This is typically going to be in the form of assert thing and assert not thing. So for assert equals, you have assert not equals. Assert contains, assert not contains. Assert array has key, assert array, not has key, assert count, assert not count, so on, so forth. But like I mentioned a moment ago, everything kind of boils down to that search for true or false. So we have assert true or assert equals, which is essentially, hey, assert true expected double equals actual. We can do assert not contains is basically if we're using it on an array, it's doing an assert false on an array. If we're doing regular expressions, we're doing preg match and seeing if we got a result. So everything comes down to true or false. When we chain all of our tests together, we can get a nice output like this. Here we can see 511 tests, a total of 1,085 assertions. Four tests were skipped. It took 1.13 minutes to run and occupied 42 megs of RAM. If we had anything that went wrong, I mean you can see down here, okay, but incomplete skipped or risky tests, those are those S's up there. Each dot represents a test method that passed. If we had a failure, we might get something like this where we see a big red F and it tells us exactly where things went wrong. There was one failure. It was in copy test, test get good copy. We were expecting great well balanced copy and we were given Starbucks. So clearly we have failed. I mentioned test doubles earlier. There are five types of test doubles and I have a sister talk to this one called testing like you've never tested before because you haven't. I was giving this in San Diego last year and my friend Jessica Maurerhan, some of you may know her. She's not a WordPress person. She's in the larger PHP community but she was sitting in the audience and she's like, Steve, you only have three types of test doubles up there and there are five. What are you doing? You're wrong because she and I have that kind of relationship where we can just call each other out for being wrong but she was right. I omitted content. So here today you get all five types of test doubles. Yes. First, we have the noble stub. Now a stub you're going to set the default response values. You're saying I expect to call this function or this method and this is the value I expect to get back because again system under test you don't want to have to test some other API to say, well, I expect to call it with these values and then hopefully it'll give me the response that I'm expecting back. I'm going to say, no, if I were to call this it would respond back with this value. We have the mock and a mock is going to let us say I want to make sure that for instance this method is called two times with these particular arguments. A spy flips a mock on its head and rather than saying, hey, I'm going to call the mock and expect it to respond in a particular way you basically say, hey, go watch that functionality over there because I'm going to ask you questions about it later to say, hey, did it call that method two times with those particular arguments? We get into the dummy and a dummy is going to do nothing but satisfy requirements. If you're working in more typed PHP so move to PHP 7 for everyone's sake please but if you have type hidden dependencies that you need to satisfy a dummy is really great for that and then you have fakes and a fake is going to be an implementation of a contract or a system that you're not using in production it basically just swaps it out to go no, maybe you have a logger for instance and you want to make sure that messages are written to the logs so you sub in a fake logger that then you can go back and be like tell me everything they got written to you rather than actually writing out to the file system or sending them to a log aggregation service or anything. After I gave the talk and left out dummy and fake before like I said Jessica kind of made fun of me then she wrote this blog post and made me copy edit it for her but it's called the five types of test doubles and how to create them in PHP unit it is in the notes for the stock highly recommend reading it because she does a much better job than I do of explaining the different types of test doubles and how to create them in PHP unit because that's literally the title of her article there's also a library called mockery that's very popular it does admittedly sort of blur the line between a mock and a stub so that's something to be aware of but it gives us this nice expressive interface so let's say we have a an API method called get recent orders and we want to make sure that it handles when we get an empty order list so perhaps we create a mock of our API class we are making a partial mock which just means anything I don't explicitly tell you how to handle proxy it back to the original class and we say the API should receive get all orders exactly once and it should return an empty array now if we have a method called get recent orders we're going to assume that that's going to be empty if get all orders is returning empty so we've been able to mock that we're not actually calling out we don't have to like create some fake you know hey look there are orders in a database somewhere and now there aren't so we're able to mock this out I could talk about test doubles all day but it's going to it's a rabbit hole let's be honest run just run there's also if I may do a little bit of self promotion sometimes you need to test markup and you need to be able to say hey does this button exist do I have an element with this class and you can do this by saying like assert contains and look for specific strings I do maintain a library called PHP unit markup assertions it's essentially a wrapper around DOM document so you can do things like element selectors you know I'm looking for something with a class of both button and active in the output so that's very handy it's available for free on github so check it out if you have to do things like the short code have the elements I expected to have now that was more general testing in PHP let's shift our attention and focus more on testing within the context of WordPress the core test suite is what WordPress core itself uses and it's arguably going to be one of the best ways to test our plugins and themes as well we can scaffold our test suite if you don't already have tests in your plugin easiest way is going to be through WPC Li they have this lovely WPC scaffold plugin dash tests and then you give it your plugin name you can also do theme tests and if you're generating a new theme or plugin through WPC Li you can say yeah no no include tests and it'll put that scaffolding in place for you what do we get through WPC Li scaffolding well we get PHP unit dot XML dot dist this is our PHP unit configuration file totally stock PHP unit basically defines this is where our tests live within our file system these are things that should be considered for code coverage these are environment variables we want to set anything like that we get a PHP code sniffer configuration file if you're using Travis CI it'll generate a Travis dot YAML file if you're using other popular CI providers you can specify an alternate CI provider there as well the install WPC test dot SH script will make sure that you have a test WordPress environment the WordPress core test suite does require an instance of WordPress that it can test against and wipe out the database of so don't use your production instance if you're using a tool like VVV it's already going to have a test environment built in which is really nice you can specify it via an environment variable to say hey do all of the tests over here you get bootstrap dot PHP which we're going to look at in just a second and then you get a nice example test because who doesn't want a test kind of saying hey here's how things might look for you one of the important things that we don't get though is a composer dot JSON file composer has yet to really take off in the WordPress space which is a bummer still holding out hope but if you haven't worked with composer composer is a package manager for WordPress if you are more familiar with NPM in the JavaScript world think of composer as a better NPM but for PHP stuff instead of JavaScript stuff so if you run composer init it'll give you a nice little walkthrough and eventually we're going to get a file that looks like this this is my composer dot JSON I'm specifying the plugin name, a description for it I'm specifying the type as WordPress plugin and then able to say hey it's a WordPress plugin so I want you to install it into WP content plugins which is awesome license information, author information and then down here I have this required dev this is where I'm loading in development dependencies and in this case I'm explicitly loading PHP unit some people will use a global PHP unit installation or something built into VVV or whatever development environment they're using however different versions of PHP unit will have different structures or different requirements around them and sometimes you'll get a test that will be working in one and failing in another and it's probably not an issue with PHP unit it's just Sebastian Bergman is very cool with like no there are going to be backwards compatibility breaks because modern PHP folks it's worth noting here I am pulling PHP unit 7 because WordPress as of the time of when I put these slides together and then check the ticket two nights ago WordPress core does not yet support PHP unit 8 there's an open track ticket for it but modern PHP is usually not the highest priority that bootstrap file I mentioned earlier that gets scaffolded for you the general gist of it as we go through we're going to locate the WordPress installation it's looking for the environment variable WPTestsDur again if you're using something like VVV it's already going to define this and say nope use this one over here otherwise it's going to assume that Michelle script installed it to temp slash WordPress testlib next we're going to load one file from that test directory which gives us access to the test add filter function we're going to write a hook or we're going to hook in using that test add filter function I wrote line as a closure because we're all using PHP 5.3 and above and because otherwise it wouldn't fit on the slide and I'm loading the main file from my plugin so I'm simply requiring that on any plugins loaded and then I'm going to bootstrap WordPress core this bootstraps the core test suite it starts going okay let me set up the WordPress instance make sure everything is the way it needs to be and then start running through the tests if we were just writing regular PHP unit tests our test classes would look something like this we have my app test extends PHP unit framework test case if we're working in WordPress we're just going to swap this out and instead of extending that base test case we're going to use WordPress's WP underscore unit test case and then get into our test methods PHP unit offers us a handy little feature called fixtures if we have common actions that we're repeating over and over I always need to scaffold a user before I run any test in this test class we might use a fixture so you can say I want to do something on setup this is going to run before every test every test method carry down after every test method we also have set up before class which will run once at the beginning of the test class tear down after class at the end of each test class we also have annotations we can do at before and say do something before each test method we have at before at before class at after and or at after class annotations are weird to say out loud again we don't use words vocalization difficult when we have tests especially if we have multiple test suites if we have multiple test classes perhaps there are features that are a little more tightly coupled and we want to make sure anything related to this one thing are tied together I want to be able to run all of those related tests at once that's where this at group annotation comes in see that one I can say out loud at group so say we have our test includes private posts maybe this includes both it's relevant to posts and post meta we can use this at group and then by running PHP unit group equals posts any test class or test method with posts as its group will get run so that's a really nice way it's totally flexible you can arrange it however makes the most sense for your application but we're able to keep this stuff together which is awesome if you recall earlier when I had the skip tests we do have these two helpers available to us through PHP mark test incomplete and mark test skipped they behave in a similar way but they have slightly different meanings an incomplete test is really great if say you're developing a new feature you're trying to practice TDD and you're like okay I know that it's going to have to do this, this, this and this and I want to make sure that I'm testing in this error case so maybe you stub out a bunch of functions or test methods but you haven't had time to actually write the test you might mark them as incomplete, just kind of they're here to remind me to write this test mark test skipped on the other hand this is typically going to get used if you have maybe an issue where all of your tests are running fine then one test fails and then everything after that starts erroring or failing and you're like am I polluting something here, am I testing that cleaning up properly, what's going on so I just want to temporarily remove something from the test runner that's where mark test skipped comes in really handy if you have a production code base where you have a bunch of test marks mark test skipped that could be a code smell that someone's basically like I can't get these tests to pass clearly not my code it must be the tests that are wrong so people just sort of remove it and then things fail data providers are one of my favorite features and I realize that this talk kind of went like let's talk the WordPress stuff let's go back to all the cool people and stuff but I get like abnormally excited about data providers if you have a similar scenario that you're setting up and it's just kind of same play, different actors you can use data providers to inject different data into it in this case we specify okay data provider I want to use my data provider which refers to this method down here I have the same setup and I'm taking arguments so expected and actual and then I'm doing the same assertion admittedly you'd normally see much more in here but for the sake of privacy on a slide I kept it pretty low but down here we have my data provider which is returning an array we can give each one a description so we might say like I want to do a URL parsing I've done that one probably a hundred times I should really abstract that into a composer package come to think of it but maybe you're saying I want to make sure that like I'm finding all of the matches for a YouTube URL so you might have like full YouTube URL short URL with query string whatever you can define all of these things and then these arguments are going or the the returned arrays are going to correspond to the arguments so the first time we run through it we'll have description of case one foo would be expected bar would be actual second time description of case two bar would be expected as would be actual we only need to do these data providers once and we don't want to break it out into a separate method there's also this at test with annotation which is really nice we can put it in the doc block at the top of the test method again foo bar would be expected an actual respectively one caveat here we can't do any sort of variable interpolation we can't if you're trying to use constants or call another function anything like that you're going to have to use the first method with the separate data provider because this actually is a method that returns an array but if you're just using kind of simple data oh I had the word and it was awesome I was going to blow you all away with how smart I sounded and now I've lost it damn but yeah the simple data that I can't remember the scaler, scaler types, boom anyway alright the rest of these I put a nice W up there to show you that these are WordPress specific uh so here's what we came here for right factories are included in the WordPress core test suite and these let us easily generate test data so maybe we need to generate posts or we need to generate users or comments or terms or attachments we can do all of that with the core test suite which is awesome we could say okay this factory post create and we could pass it an array of arguments to change what the post will look like but this is back a post ID of a post that it just created it's not going to be like award-winning post content I think it says like this is the test content but I don't have to create that post I'm not calling WP insert post and pretending that I uh have that kind of time if we need to get back the object that was created we can use this create and get so we're doing this factory post create and get which gives us the post object if we want to change just a few things if we say the post title I really want to make sure that it's my test post because maybe it was like example post before or I need to assign a particular author ID to it I can pass the post offer there those just get passed straight through to WP insert post we can also do create many if you need to for instance say okay I have an author that I've created and I need to create five posts and assign them to them you can do that by creating the author and then you take the author ID and you set that as the post and you just create many with five so a lot of cool stuff that you can do with factories a common use case within testing WordPress is going to be impersonating users if you need to make sure that for instance someone who has an author role can't blow stuff up usually that's reserved for admins right we don't want our authors blowing stuff up maybe editors sometimes but usually only administrators or super admins get to blow stuff up so we're going to create a new author level user we're going to use this WP set current user to their user ID and then we're going to do like a capability check can the current user blow stuff up we want to assert that that's false and because we're acting as them by doing this WP set current user this will return false and hooray only the admins can blow stuff up the core test suite gives us the go to helper and it's going to change the current page context as if you visited a new page keep in mind it's not actually going to make that HTTP each I added an extra T HTTP request but it's going to reset things like the super globals the globals the query variables the main query as if that page has been requested so again not an actual request which is good on saving time but something to be aware of so in this case we have look I'm not on the home page and then I go or what evaluates is home which is the page for posts which is confusing because legacy so if we go to slash blog now we're expecting is home to be true because we had set that as the page for posts in this particular site a custom assertion included with the core test suite is assert WP error which again because everything comes down to this the search for truth is essentially a assert true instance of WP error but it can be really nice if you have something that for instance might return a WP error and maybe you want to make sure that what you get back is in fact a WP error object so let's start talking about writing our first test I've given you the tools the knowledge I'm sure you could all go out right now and start writing tests and be like I'm confidently testing WordPress but for those who would like a little walk through I guess we okay let's do this so as we go through these tests I want you to pay attention to this pattern arrange act assert arrange we're going to set up the scenario we're going to generate any posts that we need we're going to set any filters that we need whatever act we're going to actually execute the code the system under test then we're going to make assertions we're going to verify that things happened in the test the way we expected them to so let's go back to the idea of testing permissions because again really this ends up coming up a lot at least in the work that I've done throughout my career imagine we have a function that clears the site cache but the function itself is checking user capabilities before someone does something if the user doesn't have permission we should get back a WPR object so up here we're going to start by changing the test like we did in the previous one we're going to create an author so we're using the user factory we're going to impersonate them and then we're going to try calling my plug-in clear cache we're going to save the response to that it to a response variable then we're going to do a certain WPR response because we expected an author would get a WPR back and maybe we want to do something like make sure that the error code that we get back with the object is a 403 does that kind of make sense to everybody we're setting up the scenario we're acting on it and then we're making assertions maybe we have a custom post type I mean I'm guessing at least one or two people in the room have registered a custom post type yeah okay I was underselling it has anyone not done a custom post type before they're awesome set all right so we register a custom post type in this example we'll say that it's book maybe that gets registered by a function in our plug-in called register post types because naming things is hard so then we're going to get the post type object of book stored in post type here then we're going to start making assertions about that now we don't have to check everything we don't want our code to necessarily have to redefine like you don't want to write your code twice once in your time once over here but we want to make sure that the key points stick we want to make sure that the post type actually got registered get post type object we'll return no if it doesn't exist so this makes sure that books are actually a thing big fan this maybe we want to make sure that the post type is public because if you happen to set it to private suddenly your plug-in will break in all sorts of mysterious ways so we're going to make these select assertions we're not worrying about things like make sure that the actual is exactly this or anything like that and maybe we want to make sure that it's hierarchical or it's not hierarchical so we put an assertion in there we can test hooks as well if we want to make sure that a custom action was called we can use the function did action which will return the number of times a particular action was called in this case we're there's nothing we have to arrange we can act and call and function and then we're going to make sure that we're seeing exactly one time that my act or my plug-in underscore action was called as we called my plug-in function if we want to get a little more introspective and this is also where the test double start kind of coming in we could actually hook into that action I've used this pattern plenty of times where you set up a variable something like called or did stuff or whatever whatever that sparks your mood that day then we're actually going to register a callback on the my plug-in action we're going to pass it a closure here and using the use keyword we're going to make sure that we're passing in this called variable by reference so if we make a change in here to say hey called is true then that's actually going to change it out here in this scope down here we can call the function and then make sure that we're asserting true in here we can take in any arguments we need to right here so arguments that would have been sent to the function and we can do additional assertions this makes sure that it's not just saying hey you passed because I never actually did the assertions in there and in here we can do did it receive exactly these arguments did it behave in this way did stuff blow up unnecessarily were errors triggered anything like that WordPress has a tendency to print a lot of things to screen things like the title come to mind where you're not returning a value you're simply echoing that to the screen so a lot of template tags short codes things like that are often going to echo things well not short codes don't do that with short codes but things will often be echoed directly to the screen so it's important that we're able to test output I prefer this pattern where you do the OB start this is PHP's output buffer if you haven't worked with it before basically it says hey don't print anything just kind of keep it in memory then I'm going to call do short code pass the short code tag that otherwise would be in my content and then OB get clean basically says reset the output buffer but also return anything that was printed since I started the output buffer so basically I'm able to get the output of do short code right here in the output variable and then I can do assert contains if I needed to get deeper into it make sure that certain selectors existed or anything that's where that PHP market assertions library I mentioned earlier comes into play if you know exactly what content you're looking for you can do kind of the short version and just say hey expect the output to be exactly H2 latest posts closing H2 and then just call do short code this doesn't let you do kind of partial matches or like hey let me throw some variables in here and kind of whatever but if you know the exact string you're looking for this is a nice clean way to do that and one of the most common use cases you'll run into is stubbing HTTP requests again we should not be testing the API is that our our themes or our plugins rely on that's not the job of our tests we have our system under test and if the API over there changes like that's kind of on the API the pre HTTP request filter is the way that we're going to short circuit WordPress HTTP API a lot of words there short circuit the WordPress HTTP API so that would be WP remote get WP remote post all of that normally this filter is going to do nothing but if we return something it goes oh I already have a response I'm just going to not execute the stuff where it actually makes calls so in this case we have to return something in this form because this is how the HTTP API responses look so we have like headers and body in this case we're saying okay we have an empty body but a 200 okay status code if we needed to test like well how will this respond if I happen to get back a 404 from the API or a 401 or anything like that we can start changing these values we never actually call out to the API but we can predict the responses that would be coming back because we're literally the ones providing them so let's take all of this and put it together there's a concept if you haven't heard the term TDD before or you haven't practiced TDD before test driven development it's it can seem like a foreign concept general idea of TDD is we're going to write tests before we write any actual implementation to describe the functionality or behavior of our code so we say okay I'm going to be writing this function and it's going to need to be able to accept these kinds of arguments and when it gets these particular arguments I'm expecting to see these responses we're writing the tests before we write the implementation now these tests are going to be failing because of course we haven't written anything to make them pass we're just saying oh this function will do this it's doing like the sales pitch and now the developers have to come in and be like oh no we actually have to implement this thing now we're going to write the code the minimum amount of code necessary to make those tests pass we've described how it should work now we have to actually satisfy that contract we have to say okay what code can I write to make this work test surpassing then we can go back we can start saying well this could be done in a more performant way we want to use functional programming here because it's so hot right now that's where you can go back you can refactor you can try to make things better before the first time you write the code you're writing just the bare minimum to like have we satisfied the requirements or if you're some people I know you never go beyond the bare minimum but I'm not making fun of Seth or anything sorry Seth I had to pick on someone yeah so this is often referred to as red green refactor red because we're in a failing state when we've written the test but we have not yet implemented the code green because the tests are passing yay green is awesome and then there isn't a good color for refactor so it's just to stay in plain old text where TDD becomes really handy is in what we call regression testing so this is a way of making sure that you have a bug you want to fix it once and never have that bug come back again now imagine we have this function called recent posts heading and it's going to take an array of posts and if it's empty it'll say there have been no posts in the last 30 days otherwise it'll say there have been X posts in the last 30 days some people might see where this bug exists already so if we run this with zero posts we're going to see there have been no posts in the last 30 days cool if we run it with one one posts in the last 30 days I'm not cool with that that hurts and then two posts in the last 30 days okay we have a bug in our software it's making us look like we don't understand how pluralization works let's write a test for it let's say we maybe hadn't had any tests before because we're just getting into writing tests so we do something like this we have a data provider and we're saying okay when I have zero one or two I'm expecting there have been no posts in the last 30 days one post one spelled out because one as a numeral at the beginning of a sentence is awkward one post in the last 30 days or two posts or X posts whatever so we could keep going on saying like at 15 we want it to you get the idea so in our test we are using a factory we're creating many however many we tell it here we are setting the expected output to expected which again is going to be the string there and then we're going to call recent post heading on the post array that we generated now we haven't fixed the bug yet so our tests are going to be failing we still have a situation where we're looking for one post in the last 30 days but we're still getting the number one posts in the last 30 days I die a little bit inside every time I have to say that so we look at our code and we go okay we've been able to reproduce the bug we have something telling us hey there's an issue here you've reproduced it and we add in an additional conditional statement so we say okay if we have exactly one print one post in the last 30 days for everything above one so we've covered one everything else do X post in the last 30 days now our tests are green they're passing we get to go to Chipotle or Happy Hour or whatever what's important here is that if someone comes back and maybe we have a merge conflict or someone's like I really hate el-sif because there are people who are like they refuse to use el-sif and I don't understand it it doesn't make sense to me at all but if you want to sacrifice a third of logic cool maybe they remove that well suddenly we're going to go back to a failing test because we have this test in there saying hey it needs to cover this scenario so we will hopefully never have to solve this bug again which is awesome because I hate repeating myself despite the fact that I do it over and over and over so with that we have like two minutes I don't know if it's a 45 or 50 minute slot timing do we have time for questions alright either way let's do the clappy thing now are we all confident testers do we have time for questions yes okay so if I'm understanding correctly basically how do we make sure that after we say we're not actually going to call out to the API we're going to stub everything and then what if that API changes or they introduce something new and things break in all sorts of miraculous ways I've done that more times than I care I've actually started writing like side tests that just kind of get run not as part of the main test suite but rather as part of like hey this is what I'm expecting to get once a month on like a cron through a CI server like call out and make sure that like the responses still sort of match part of that speaks to API versioning as well some people will just break things I've already been pretty critical of Facebook today so I'll give them a break here no I won't they do that a lot and it gets really painful but yeah you get into kind of this sub thing so what you want to make sure that you're doing is if you can't know that things are going to change but you want to make sure that you can adapt quickly I often will write helper methods that'll kind of be wrappers around that API so I'll have like a mock this request and I'll pass in the relevant data that I need for my individual test case but I will have like a single method that kind of this is what I'm expecting to get back and I can fill in whatever details I need to but if something breaks I can go oh this is okay this is how it broke and this is where I can change it in my test so moving forward things are cool changing APIs that's kind of one of those like we're going to build everything built on everything else as long as nothing changes we're cool unfortunately that's rarely the case so is it one more that I have time for or was that the one that was the one okay if anyone has further questions I'm around the rest of the day I will be at the the after party as well and thank you all so much