 Alright, it's time. Let's get started. Welcome to Principles of Unit Testing. I'm Joe Purcell, the development team lead at Digital Bridge. I've been working with PHP since 2003. Our goal as a company is to make a difference for B2B companies in Midwest who are looking to move into the digital channel. We're hiring, so find me afterwards if you're interested. Who are you? My expectation is that you are intermediate in terms of familiarity with unit testing, and by that I assume that you've either worked with unit testing before, or you understand the topic well enough that you're ready to have whatever assumptions or ideas you have about unit testing to be challenged. This will be more advanced for some, not as advanced for other people. This talk, the nature of it is going to be more, it's going to be less entertaining. So it's going to be more digging into specifics and definitions. So the goal we'll get to in a minute. I want to tell a story first. So if you've not read Mythical Man Month, I encourage you to do so. It's highly relevant to us. This picture is of a tar pit. If you've been to LA, you may have seen the tar pits there. This image shows huge beasts that are struggling in the tar. Programming can be very much like this, where teams, no matter the size, big and small, have struggled with projects that are missing goals, missing schedules, missing budgets. A lot of them still have running systems at the end, but I think most people are surprised by how difficult it can be when all of these factors come together. If we want to get better at writing code, we need to understand these problems. So with that goal in mind, there's two things that I want everyone to come away from this conversation today. I want you to understand what unit testing is. So if you don't at any point along the way, please shout it out. At the end, you can come up to the microphone and ask questions. I'll save some time at the end. But I also want you to understand when unit testing is valuable. So when you go back and you're working with your teams, I want you to be able to articulate why or why not you would want to unit test. The way we're going to accomplish that is we're going to go through a definition first. We'll talk about two principles. So if you're taking notes, write down the phrases test doubles and solitary versus sociable. Those are the two principles we're going to cover. We're going to go through some examples. So when we go through the definition, if it doesn't make sense, we'll show some examples. We'll talk about some test smells. So over time, as you apply these principles, you'll notice some patterns that make writing unit test difficult. We'll talk about those. And then last, we'll talk about motivations. And that's the persuasion around why you would want to unit test. Some of the examples that I'll show you are a little contrived. Some of them are very simple and fabricated, but intentionally so. Bear with me. Examples are hard. Also bear with me because we're not going to get through all the content here. But I'll make sure that we at least touch on them so that when you go back and you want to do some further reading, you at least are aware of the topics. All right, let's dig in. Definition. Raise your hand if you're frustrated by the definitions provided around what unit testing is and how it compares to other types of testing. Maybe half the room or so. Okay. I think there's a number of problems that we face when talking about a definition of unit testing. One is the ones that are out there, a lot of them are ambiguous. So you can't be specific if you're dealing with an ambiguous definition. It's hard to articulate. The books and blogs out there, a lot of them use different terminology. And then even across languages, there's a lot of differences. And the tooling that's used for testing across languages is even inconsistent then. So all of this combined, it's frustrating. It's hard to move our understanding of unit testing and how we do unit testing forward with such an ambiguous starting point. I want to point out for a moment. If you look at other industries and how they've evolved, definitions are foundational. They're so important. So one of the things that we're going to try to accomplish with this topic of definition is to make this point clear. What is a unit test? Wikipedia is quoted a lot of times. So if you search and Google what's a unit test, you might see Wikipedia quoted by bloggers and such. But it's pretty lengthy. It's not very specific. If you've seen the X unit patterns book, I think it's pretty close. But it's still, it's more ambiguous that I would want it to be. I like what Martin Fowler has to say about this. He says it's a situational thing. The team decides what makes sense to be a unit for the purposes of their understanding the system and its testing. I like this because it gets at the nature of it, like how we should approach it collectively. But it's not something you'd really build a definition on. It's not something we collectively can build an understanding together. And a recent article that he posted, he even calls this out. He says the software development community simply hasn't managed to settle on well-defined terms around testing. Well, I think this is the wrong stance to take. I think we need to define this. So let me propose to you that this is our definition. A unit test verifies a unit's correctness against a specification. We'll elaborate on this. There's a couple of things alike. One is that the phrases verify and correctness has its roots in formal verification. I also like this because there's nothing you can unit test that this definition wouldn't apply. But what is a unit in this case? A unit is a function. So if you use the t function in Drupal, that's an example. It could be a method on a class. Like if you have a block, there's a build method on it. It could be a script, like update.php. It's one thing, like it's one concept. If you've ever used a step debugger or a stack trace, think of it that way. Think of a unit as a single step in the stack or a single stack frame. In terms of terminology, some would call each one of these a subroutine. So you might see the phrase subroutine used. Each one of these could have a unit test written for it because it's a unit. Simple example. Let's say we have a function. It just takes a parameter that's a, adds the integer one to it and returns it. We have a test that verifies that our increment function should take any integer input to it and add one. This is our function, the unit we want to test, and here's the test. That's it. Very simple example. What makes this a little confusing is there's different levels of testing, and we'll talk about this more later. There's solitary unit testing. If you have used a unit test case in Drupal core, that's an example of a unit test. There's sociable unit testing. If you've used a kernel test base, that would be an example of a more sociable test. And functional testing, like browser test base. What makes this confusing, all of this can be written with PHP unit. So let's clarify this a bit. We'll use an example, real-world example. Let's say we're building bridges. I want to use some bridge analogies. If you build the bridge and then decide to drive a train across it to test the bridge, it's not really a unit test. You've already built the thing. This would be more like a unit test where you take the steel beam that you're going to use to build the bridge, and you do a stress test. That would be because you're testing a part of the whole. That's our definition. That's what we're going to work with. Okay, let's talk about principles. Yeah, okay. So has anyone seen Black Panther? Really cool. If you haven't seen that, encourage you to watch it. It's a really neat film. On the left, you see an image of Denai, who plays the character Okoye. On the right, you see her stunt double. Her name's Janisha. She is also one of the Dora Milaje. Janisha was a professional wrestler. She was part of the U.S. bobsled team. She did Taekwondo and gymnastics. She trained eight to ten hours a day for weeks to prepare for this role. Amazing stuff. The phrase test double in software development comes from this. It comes from the movie industry of you have something, someone, that looks and behaves like the real thing. That's where this phrase comes from. There's two challenges when you do unit testing. Let's say we had no test doubles. There are going to be problems that you encounter when trying to unit test. Those are indirect inputs, which would also be called shared state. Think like PHP globals, think config, think file system. Those are inputs to a function, indirect inputs that can be. And then also think of indirect outputs. That could be you're calling a method on another class. And that class is calling another method on another class. Think writing to a database. Think writing to a file system. Those are indirect outputs or side effects. Essentially anything that makes it not a pure function. A pure function has no shared state or side effects. Simple example to show why this is a problem. Let's say we have a function that gets a product from the database and a unit test that if you're given product ID 1 and you want to assert that you can get the product and that the product is in fact the one you requested. Well, when you run this test, when get product is called, it's going to throw an exception. There's no database. Now you could run this on like a live system but you're not controlling the indirect input. So this makes it hard to test. So you can use a test table for this. Another example would be a side effect. So in this case we're, let's say we have a product and products have favorites so 10 people like the product then the counter is 10. So we have a function that increments that and rates it to the database. Product save, it's writing to the database. When we run our unit test, it's going to call that exception is thrown, there's no database to write to. So this is just some very simple examples of how, of when test tables are needed. So let's say you have no database, you can use a test table. Okay, so test tables are the tools we use to test units that have shared state or side effects. There are five of them, we're going to go through these and we're going to pause if you have any questions about them. Before I talk about this, this is one point where I don't think I've seen any two testing tools that have the same terminology for this. I don't think I've seen two books that have a full set of the same definition of what test tables are. So what I've done here is I've scanned a survey of popular books and blogs and such and consolidated that into a unified definition that I think I can present in a way that we can all understand. So if you go searching for these afterwards and you say, oh, well, a PHP unit phrases this differently, yes, and that's frustrating. But here we are, so let's begin. A dummy is a test double that is never called. And we'll show examples of each of these, but I want to run through them so you're aware of what we're going to go through. A fake is similar to a dummy, but it is called. A stub, you provide indirect inputs. So we talked about reading from a database or reading config, something like that. A spy does the same thing as a stub, except it captures the indirect outputs. So it captures any call to another class. And a mock does something similar to a spy, but at the time of execution, it runs the validation. And we'll see what that looks like here in a minute. So let's go through each of these. A dummy, a PHP unit fun thing, if you call get mock and pass in a class, you then have essentially a dummy object that implements an interface. So if you ever have wanted to pass null into a parameter, like a constructor for example, but there's an exception thrown because like a type error, you can create a dummy class using this get mock. By the way, all these examples are going to be PHP unit. That gets passed into our vote method so that it passes the type error, but it's never called, so that's fine. And also in order to call this, we create an object dummy and pass that in. The reason we're doing this is because all that we want to validate in our test is that the default is access is granted when we try to create something. So we don't really care what the token is. We don't care what the object is. We just want to validate that the default is access granted. Another option, if you are building classes and you add default values for all your object properties, you might just be able to pass null, but that depends on how you've written your code. A fake, think of writing to a file system in this example. So a fake would be, in this example, I've written a class called fake file, and when I pass this in to the binary file response and I run my assertion to get the headers, it's going to call methods on my fake class and return could be hard coded values, for example. But notice this is different than the dummy and it is called and it is a concrete class. A stub, it's similar, but in this case, a stub is any case that you take a method and change what the set with the return value is. So instead of a hard coded fake class that you've written with PHP unit, you create a mock object, set what the parameters are. So here we're going to change the method is granted and we're going to say whenever is granted is called, it's going to return true. And the reason we do this is because imagine we're testing that a controller actually does an authorization check. Very simple example. A spy, it's like a stub, but what you're going to see different in this example is let's say we have a profile object and there's a method on that that says I want to get the full name, which is a combination of first name and last name. What we can do with a spy is we create the spy, pass that to our profile, and then after it's executed, after we call get full name, we can validate the first name and get last name was called. So you're not validating that the name is Joe Purcell, you're just validating that the method was called. And there are various examples why this is useful. And the last one is a mock. I mentioned that a mock runs the validation during execution. This is how it does it. If you call mock expects this once, that means that when I call get full name, when I execute the class under test, it's going to verify that it was only called once. It's going to verify that it was called and that it was only called once. So if it was called twice, this unit test would fail. So in this case, we want first name to be called once, last name to be called once, execute the test. That's our verification. What should you double? There are cases where you want to choose different types of test doubles. There are even cases where you may not want to double the indirect input or output to begin with. I think that this part, what should you create a test double for is something that people, I can see teams struggling with this because it all depends on how you understand whether you're doing sociable or solitary. Whether you want to test a whole bunch of code with a single unit test or you want to test just a single unit, you want to mock everything around it, you just want to verify this one single unit. Imagine we're building bridge. You could maybe test a single cable. You see the, so this shows a picture of a bridge and there's lots of support cables streaming from the arch to support the bridge. You can imagine, before you build this, you test one of those cables. That would be solitary because it's individual. It's a single thing that you're testing. Think of this on the spectrum. You could test two cables together that would be more sociable. You could try testing the whole, maybe a whole beam section that's assembled together that would be more solitary. The more solitary, the more isolated, the more sociable, then the more units are executed. Going back to the example of a stack trace, a solitary test would only execute one step. A more sociable test might execute lots of steps in that stack. This concept came from a book J. Fields wrote called Working Effectively with Unit Tests. The difference between the two is that with sociable, it's okay to cross some boundaries. It's okay to have multiple steps called. In solitary, you never want to cross boundaries. You never want the class under test to execute a method on another class. Also in sociable, it's okay to have multiple concrete classes created during runtime, but in solitary, you only want one. You only want the class under test to be instantiated during runtime. What's a boundary? We already talked about these, but the phrase boundary is important to keep in mind. There was a blog post. This is the first time I found reference to a boundary in this context. So a boundary to a class would be a database, a queue, another system. It could be an arbitrary class that's outside of the area trying to test for. For example, if it's extending a parent class, you could consider that a boundary. It's anything outside the specific unit that you're wanting to test. What does one concrete class mean? It means that any dependency, so if you open up a class and you see a whole bunch of use statements at the top, every single one of those should have a test double written for it. If you want to have only one concrete class created. It means that all the collaborators that return objects should also return doubles. So if the class you're testing calls a method on another class and that class returns something, that should be something that has a test double. It means no statics. You'll see a lot of hooks in such in Drupal that call statics. That would violate the principle of one concrete class. One caveat is value objects are okay because a value object is just, it's essentially a data structure. So value objects shouldn't have behavior to it. At this point, you might be feeling like your head is exploding. That's perfectly okay. We're going to recap. I think this is the critical part though. Getting these definitions down will help you as a team grow and be able to change how you approach unit testing. I think it's critical for us as an industry to define these in order for us to move forward. A unit test verifies unit's correctness against specification. Use test doubles for indirect inputs and outputs. There's five of them. A boundary is an indirect input or output. Sociable unit testing, you're going to cross some boundaries. It's okay to have multiple concrete classes. But with solitary, you never want to cross boundaries and you only want one concrete class. I'm going to pause. Any questions? This is the important part for the examples. You can shadow that. I'll repeat it. I just have a question or an observation. I like your definition, by the way. That's good. I work in an organization that doesn't always have, I should say almost never has specific specifications. So what do you do when a unit test verifies its correctness against a spec? I guess you'd have maybe assumed specifications, but I'm in QA, so obviously I'm looking at the big picture. My question is what do you do when you don't have specifications? I may be a broad one, but... Write the specification. Start there. When we talk about motivations, we'll talk about some different scenarios in which unit testing is valuable. One of those is if you're doing exploratory work, you can use tests as a way to help you understand the code that you're writing, especially if it's extremely complex code. So it's sometimes okay to let the person writing the code write the specification themselves. If you're in QA, it depends on what level of granularity of QA you're referring to, because QA could mean you're reviewing the actual code and you're validating, it meets our standards, code style, all that. But I assume in this case it's like... Yeah, I do. Functional as the user? Yeah, a lot of black box. I'm starting in the future to help with unit testing with just a lot of stuff going on, so it's hard to get that running. So that's a great question. I would say in that case, the specifications that I'm referring to here are at a level more granular than the level of specifications that a QA person might have. That's not always the case. Certainly at that level, those are going to affect the specification of a unit test. I just can't help but respond to say that the programming wisdom Twitter account recently tweeted out that without requirements or design, programming is the process of adding bugs to an empty text file. So I just found that so true and you have to have specifications. Yeah, yeah, that's good. Okay, we'll have more time for questions at the end. Let's move on. Examples, okay. I first gave this talk, or a similar talk a few years ago, and there's two examples I'm pulling from Drupal Core, and they're still relevant, which is fun. When you look at this bit of code, this is batch storage, and there's a method called load. There's a few... I don't know if you can spot them. Look for the indirect inputs and indirect outputs. There's a couple. I think there's three. We're calling a method on another class. That's a collaborator. So that'd be an indirect output. We don't know what this does offhand. We would need to go look at the code. It might be writing to the file system, or Redis, or the database, depending on where sessions are stored. So when you're thinking about writing a unit test for this, you may have to write a test double for it. There's an indirect input. We're querying the database. Do we even have a database with our test suite? You're calling a method on another class. Get the CSERF token. Maybe this calls the database. We have to go look. Let's try testing this with solitary unit testing. So we want to mock the whole boundary, or use a test double for the whole boundary. This is an example of what that would look like. The test I've written, all I want to test is that the load method will start the session. Because the reason that's there, I'm sure, is good. We want to validate anytime load is called, the session has started. The way I've done this is I've mocked the session. I'm using a mock here because I'm verifying this at the time of execution. So where it says this expects once, when I call load, PHPU in it will validate that it was called exactly once. We're going to stub the indirect input from the database. So when I run this test, I don't need a database. Awesome. It's going to be more performant. I'm also going to dummy the CSERF token because for the purpose of the test, I don't need that. I'm not validating that. And lastly, we execute the class under test. The problem with this test, and you'll see a lot of tests like this. Core uses a lot of mocks. The assertion is a little unclear. The assertion is that you kind of have to read through it to find where the exact assertion is. So let's refactor this. Let's revise our test and use a spy. By the way, PHP unit, I think now comes with prophecy because for a while, PHP unit didn't have the ability to use the spy test double. Now it does with prophecy. We execute what's cool about this. We execute our code and the assertion is at the end. And we're going to talk about this approach later of arrange, act, assert, like structure your test in a very readable way. So it's nice about a spy. You can always, it's a good way. So if you see any mocks used and you're like, wow, this is really hard to read, you might consider using a spy so you can pull those assertions down to the end of the test. The second example is the maintenance mode. This code has changed a little bit, but there's quite a bit going on. If you want to write a solitary unit test for this, I think, if I recall correctly, I saw a test for this and I think it was using browser test base, which I don't know, it just seemed like this functionality, there might be a good case to have a unit test for it because what you're wanting to test is like, if maintenance mode is enabled, then I want to not return the page response. I would hope there's some seam in the stack where we're going to have a unit test for that. So there's quite a few indirect inputs and outputs. I'm going to show them here. One, two, three, four different indirect inputs and outputs. The problem with this is we can't solitary test this. What do we do? You could be thinking, well, unit testing is just that hard. You could also be thinking, well, the code is hard to test. So if you think that unit testing is just hard, what you're going to end up doing is those four indirect inputs and outputs, you're going to have to write a testable for if you want to do solitary testing, which means you're going to write this huge sociable test that's fragile and probably impossible to maintain, or refactor. Refactoring is part of all of our jobs as developers. It's a good and natural part of development. So let's take that. Let's delete the untestable code and we're going to reimplement it later. We're going to break this class into two responsibilities, setting the response and showing a message to the user. So I've created an interface. This is going to handle the actual response. Think of it this way. HTML, like requests for HTML, might not be the only content type requested of Drupal. Could be JSON, could be XML. So we could have different implementations of this. I'm going to create a subscriber that overrides the page rendering. So we pass in our maintenance mode page that's going to return the response. You can see where it checks if it applies, whether the user is exempt from the maintenance page and it returns the response. So now we can test. I know at school about this, our class does one thing now. All it does is it checks is the maintenance page on and is the user an exception to viewing the maintenance page. Which means we can test one thing. Class has three dependencies now instead of six. So we've decoupled our code. It's more readable and it's easier to test. It's also abstracted. So if you're trying to return JSON response, you now have a way to do that. Here's an example of the test that you might see. We dummy the account, stub the applies method, stub the get response, stub the get request, execute the class under test, and then we have our specification which says if a page applies to the maintenance mode, then it should return, we should be setting the response on the event that's called. What I like about this example is unit testing is hard. Like thinking through a good unit test takes some time and it takes some experience. You won't get them all right the first time. Let's talk about test smells. I don't want to go through all of these in detail. So I'm going to breeze through them. This will be good reference material later. And if you're new to unit testing, you may not observe some of these to begin with. But later on refer back to this. The phrase test smells, if you're not familiar, I believe the origination was the book called refactoring by Martin Fowler. And in it there's an excerpt of Kent Beck. He was talking to his grandmother about raising child and like how do you know when the diaper is ready to change and if it smells, you change it. So how do you know when test code should be changed or refactored? Well if it's things working with it, then it's probably a time to refactor it. So let's go through some examples. Obscure test. This is the case where you look at a test and it's like 200 lines and you have no idea what's going on. One example of like reducing the amount of code is if that test has a lot of setup. You could use an object mother, which is essentially a class that returns the object you're trying to build. Maybe it's returning a fixture for example. Something similar is called a data builder. So unlike the object mother that returns a specific object, data builder would let you build the object you want and return it. So in this example you could see like let's say I want a user that's inactive with 10 posts call build and return that user but maybe we want a user that is active with five posts. So a builder is more dynamic way to create fixtures or mocks. You could use a custom assertion so if your test is obscure because all the assertions are like really complex and like 30 lines, you could take all that code, put it in the method. So in this case all we call here is assert link and let's say this assert link has a lot of complex logic to verify that the result of the link generator was correct. I've seen a few cases in core where a custom assertion might make sense. Some tests are obscure because variables are passed in. Try to avoid doing that because if this test failed you have to go read through the, in this case the class variable and trace back how that variable was set to know exactly what the output should equal. So instead of passing a variable in an assertion use explicit literal assertions. Another pattern that you can use to address obscure tests is a range act assert. This is brilliant. So Cunningham Ward, I found this on his blog, the idea is you break every test into using white space, you break it into a range the preconditions or inputs at the very top. So that might be creating all your test doubles. You do the very top of the method. In the middle of the method you act. You call the system under test. At the very bottom you do the verification. What this means is if everybody did this it would mean that you could pick up any test that failed and know exactly okay I'm reading these lines of code because it's setting up what we're going to call and here's the verification at the very end. If you follow this I think you'll find you'll use mock test doubles less. So that was just a quick example of what that would look like. So easy to read. Assertion roulette. You have a test, it's failed and you don't know which assertion has failed. This is probably common if you have a mock that is stubbing like five methods and they all have expects with, you know, explicit values that should be passed in. These can be pretty gnarly and frustrating. You could try one assertion per test. So a lot of tests in Drupal core and on projects I've seen will have like a test that basically tests all the functionality of a single class. There's a few problems with that. It can make the test obscure and it can make the test hard to figure out what actually failed. So in this case I actually pulled this from core. This might be from 8.3 or with this slide a while ago. But there's four different assertions in this test. So if it fails, which one of these actually failed? Yeah. Oh, five, sorry. A better way would be to just one assertion per test. Makes it much easier to debug. Keeping in mind, part of our day to day, we spend a lot of time debugging. Like if you're maintaining a project or writing a library. Fragile test. You refactor some code and your test passed for that class but all of a sudden all these other tests are failing for some other class you didn't even touch. This is really easy to do if you have high coupling in your project or a lot of side effects. There's a few things you can try. Eliminate dependencies, eliminate those side effects in shared state. You can try the one assertion per test. Avoid test over specification. This means that if you have, if you're verifying that a class returns something specific and you're also verifying that a collaborator of that class is returning something, that would be over specifying because you're reaching beyond the class under test. Code duplication. There's a few things we already talked about. You can use an object mother or data builder. You can do abstractions like browser test base, for example, as an abstraction. Sometimes the cost of maintaining it doesn't make sense. You might be doing the wrong strategy. Unit testing might be the wrong choice for the code you're trying to test. Negative or low return on investment test. You can remove them. That's okay. Object mother, data builder, add abstractions, avoid over test specification. Okay, motivations. This is the part we're going to talk about why. Why would you unit test? Bridge analogies. Let's say I have a co-worker who's done a lot of traveling. She provided this photo from Congo. Imagine you're building a bridge. Maybe there's not a lot of value to testing. Every board that goes into the bridge and going through months of testing, maybe it makes sense to just build the bridge and that's okay. There are some projects where maybe that's fine. Maybe it's okay. Maybe the impact of a bug is very low. There are cases where there's a high level of benefit. Even small bugs pose a higher risk to the organization or project implementing this. This photo is of one of the train bridges in Chicago. One million people use the Chicago trains every day. Imagine if one of these bridges failed. That would be catastrophic. Unit testing can provide a high level of benefit, making sure that every part of the system of building is correct. When does unit testing have high value? Use the rule of three. If the code you're writing, if there's three or more other classes or use cases for the code you're writing, it might benefit from a unit test. If you're writing a library, if someone's using Composer Require and they're requiring the thing that you're writing, unit test. It will provide high value. If you are working with legacy code, you may want to write a unit test, especially if you're not certain what all is calling the method on the class that you're going to refactor. Even if you don't encapsulate all use cases, if you deploy it and it breaks, you at least can go back to the unit test and be like, okay, which scenario did I not account for? So writing the unit test before you refactor can help you create a baseline for how to move forward. If there's necessary complexity, I was actually trying to think of some examples where I felt like high complexity was absolutely necessary in a method. Usually complexity is the case where it's like we don't have time to refactor. But in any case, let's say you have a method and it's really complex. Unit testing will provide value there. Let's say it this way, if you look at a method and you can't hold in your mind all paths through the code, it might benefit from a unit test. Exploratory work or doing unit testing to assist development like TDD might be a case where unit testing is helpful. If there's high cost, even minor bugs, financial software, for example. If you're writing a framework similar to a library, but let's say you're working on the symphony project or you're working with Drupal Core, Drupal Contrib, should be writing unit tests. There's bound to be something in there that at least three other people are using. When is unit testing not so valuable? I would love to talk to you all afterwards about this, but I think that most Drupal projects may not benefit from unit testing. Because most of it's glue code. Most of it would probably benefit from a test at a higher level. So like a functional test or a browser test, for example. If the maintenance cost is significantly higher than the cost of a bug, maybe you don't want to unit test, and that could be okay. If you're writing code in a platform, this is similar to the first point. If you're writing code, maybe it's a theme function for WordPress or a theme function in Drupal or something. There are certain cases where a unit test within the context of a project that's leveraging a platform like Drupal, it may not provide a lot of benefit because you're relying on the platform to be stable. Yeah, it would be kind of a chaotic world if you had to write unit tests for all of the code that was leveraging a platform because the platform was so unstable that it would be unfortunate. If there's a more valuable form of testing with lower effort, so in the case I mentioned, I think a lot of projects would probably benefit from, say, the HAT or some other type, like Selenium, some kind of functional testing, might benefit more by using an alternative form of testing than unit testing. Solitary versus sociable, I'm going to breeze through this because I want to get to another section. Sociable tests, they're hard to debug. Have you tried writing a kernel test in core or had to debug one? It's a bit difficult. Solitary unit testing, there's a lot of benefits to it. It's going to execute faster. If you have to write a lot of test doubles, you're going to think, you know what, I'm not going to write that test double. I'm going to refactor my code and make it less coupled. It should not underestimate how much easier it is to test pure functions than their state-filled counterparts. Solitary unit testing forces you to write good code. So the story of the Lorax, it's a story about pollution and the once-ler would not listen to the Lorax who was saying, you're destroying everything, like you should stop doing this very bad thing. It can be hard to communicate the business value of doing unit testing. But where it's appropriate, you should. You should be the Lorax. The code does not have the ability to speak or defend itself. You are the professional in the room who should understand the value of unit testing and be able to communicate that. Example of the Lorax. One of my co-workers, Kyle Einigry, sent me this message a while back and it was just, this is why Drupal8 is good and sent me a link to an issue thread. So I opened it up. Someone had submitted a patch, said it's ready for review, and a maintainer came along and said, sorry, but we can't just commit this. Supporting comments won't help here. We need tests. That's being a Lorax. That's stepping up for the code and saying, other people depend on this. Let's make sure it's stable. So where do you start on your project? I recommend a tool called PHP Metrics. There's a lot of static analysis tools out there. But go get a baseline. Like figure out where your code is highly coupled or where it's highly complex. So this chart, it shows 8.5. It shows some various things where there's high complexity as you move up the y-axis and high coupling as you move across the x-axis. Those are good cases where you might want to decouple or lower the complexity of your code. Think about symphony. It's good object-oriented code. There are a lot of projects that are reusing symphony. It shouldn't surprise that there's a lot of solitary tests in symphony. So something to think about. So remember the principles of unit testing. Use test elbows. And apply the principle of solitary versus sociable and which one's going to be more appropriate for you. All right, thank you. I believe we have a few minutes, so let's talk. Does anyone have any questions? And we can also talk afterward. Okay. Thanks everyone. The slides are available online. You can also rate this session. I'd love to hear your feedback. The slides also include some references from the presentation and for the reading. Good to see you. Likewise. Likewise. You as well. I know. I saw you up there. Yeah. Yeah. It was good to see you. I feel like it's... I don't know how long it's been. Have you ever seen you at maybe New Orleans? That was it. Yeah. I think we bumped into each other in New Orleans. Yeah. About two years ago now. Yeah. Good. Thank you. It's hard to... Yeah. It's just... It's hard to know... Once you immerse yourself in the topic, it can be like fish and water. Because you're like... Oh, well, of course, everyone knows that. But it's not the case. Having never written a unit test personally, I was still able to follow it on 90%. Oh, good. Good. Okay. Let me come down there.