 Just before I actually get into it, how many of you guys have done automated testing before? Oh, quite a lot of you. Unit testing or B-HAT? Unit testing right now? Both, okay, and only B-HAT? Something else entirely? All right, we've got a really good mix. All right, this is testing for the brave and true. I'm Gabe Suleese. I work as a back-end engineer at Atten Design Group. My email is Gabe at atten.io. You can find me on GitHub, Drupal.org, or Twitter, as Gabe Suleese, and that's pretty much everywhere. Atten Design Group is a full-service digital design, strategy, and development shop based out of Denver, Colorado. We work mostly with universities and nonprofits. Mostly we just like to say that we help tell the world's most important stories. To start, I'd like to say a little bit about why I'm up here. And that's mainly because I think discussions around automated testing have often left people really far behind. I hear people say things like, if you're not testing, you're doing it wrong. That can be kind of frustrating because it's kind of like don't tell us that we're doing it wrong, just tell us how to do it. And let's be truthful. Testing isn't really all that easy to get started with. Mostly because documentation is kind of terse and aimed at core developers or maybe maintainers of big contrib modules. And so learning the basics can be kind of difficult. It's difficult to find good examples and it takes time to develop the good habits that makes automated testing easier. But the rest of the programming community at large has been doing testing for a long time. And in Drupal for everyday use, I think we're kind of behind the curve. And testing can provide us with all these enormous benefits. Better reliability, better security, and especially better maintainability. So we kind of have to be testing all throughout our days and all our code, our custom code, especially testing when no one's looking, right? Because if you're only testing when somebody's watching, it's gonna be really hard to go and share your code on Drupal.org or something like that and really have it well tested so that other people using those modules also get that nice reliability, maintainability, and security features. So let's go to first principles. What is automated testing? What are automated tests? Well, they're just code, right? If you can write or call a function, you can write tests. There's nothing magic about them or difficult to approach. They're just code that tests your code. If you're writing a new function and call some other function, a test just calls the new one that you're writing, right? Given some inputs, I expect to get these results. And I think a lot of us are mistaken in the belief that we think we haven't tested before or we're not doing testing every day. But the reality is that we're all testing all the time. It's just about whether we're actually keeping that work for prosperity or not. So these are some of the ways that we might already be testing. We might be doing testing in the browser, right? So you're familiar with that kind of workflow with Drupal. You write some code, you switch to your browser, you refresh the page, then you clear cache in that order and then you clear cache again, right? And then you see, did what I wrote, did the function I wrote or the hook that I implemented, did it actually do what I expected, right? So we do testing in the browser. We might do it with Xdebug. We might dump out variables using DPM, Vardump, Kint, even just print sometimes, right? And then even sometimes reading code that you're not familiar with can be a form of testing, right? You kind of step through it in your mind, making sure that what this thing you expected to do actually is doing this thing that you thought. And so that cycle just kind of repeats. Did I, what I wrote actually work? And then we just repeat it and repeat it and repeat it until we get something that's working, right? And eventually it does and then we move on. All that work that we've put into kind of discovering the edge cases, making our assumptions, validating different scenarios in our heads and spending that time to gain this mental context just goes out the door as soon as we move on. So don't throw that work away, right? You can keep that by just putting it into code. And that's all that automated testing is. When we don't commit our tests, right? We'd leave our code to just rot, you know? We come back maybe a week or a year later. And it's just, we can't even, we barely recognize it anymore. So we forget all those edge cases that we discovered. And then we have to repeat that effort. We have to regain context and whatever we're working on. And so that's where automated tests can really help. They're kind of like living documentation for everything you're writing. When you write an automated test, you're writing down those assumptions and those assertions that you wanted to make. You're saying, these are all the things that I want this code to do and solve. And so when you return to it, it's there for you to pick right up. You don't need to spend so much time refamiliarizing yourself. And even better, this is kind of overlooked sometimes, is that you don't have to do it for all the code in your entire code base, right? When you make some change over here, you can be sure that you didn't break something over there, right? And I can't imagine how many times it's happened to me, right? You go in, you're trying to fix some bug, you found some new edge case, your client called you and said, this isn't working how I expected. And you fix the problem, you're all confident, you put it up on staging, it works, and then finally it goes to live. And all of a sudden a week later, you get a phone call and oh man, this page isn't broken, it's just a white screen of death or something. And the reality is you just forgot something over here. It doesn't happen all that often, but when it does, it's super embarrassing. And so the last little thing that makes testing really valuable for me is I also have a framework to put my new, like newly discovered bugs into code, right? You've already built the framework to say here's the thing that my client did, right? They put this value in and this is what my code should have done, but it didn't. So you get a failing test and then you can work to actually fix that bug and then be assured that you did, right? Your test will finally turn green and will pass it. So all those things, right? The regain of context, the ability to put bugs into a already existent framework, those things can make you a more productive and a more reliable engineer. And so maybe I'm making all these promises but you're still skeptical and there are probably lots of doubts that you have about testing, right? You wouldn't be here otherwise. And to be honest with you, I'm still trying to get over them myself. So you might have questions like, how can tests make me more productive when it means writing more code? Or how do I find the time to write tests? How do I sell them to my client? Or, and this is the one that I found to be hardest. How do I convince myself that testing is gonna be a net benefit to me? So let's go back. Look at that one. How does writing more code actually make you more productive? And I kind of just have a rhetorical response to that, right? Why do we do object orientation? Why do we write smaller functions and break them down from bigger ones into smaller ones? Why do we break a long if statement down into multiple lines? The reality is, is that writing a little bit more code makes your code better to read, easier to understand and more maintainable over time. All those same things can apply to testing too. You just have to develop the habit of getting into it. Just like you just have the habit of automatically writing a new function or something like that, just have the habit of writing a small test. And if you've already started the framework and you've already learned and gotten over the initial humps, that won't be so hard or daunting. Or how can I find the time to write tests? Well, I think at first I'm not gonna lie. It can be really difficult. You're gonna spend more time writing your tests and more time writing your code. It's hard to understand when you first get into the habit. It's hard to write testable code. There are lots of things that you have to worry about. Like, are my dependencies injected? Am I relying on something outside of the function or a global variable or something like that? And so you can't mock that. You can't fake a test so that you can really test just the functionality of a single item. So it will be hard to start. But once you get better at it, it becomes this natural thing and it'll actually help you be faster. It'll save you time in the long run. Because if you think about all the time you've spent switching context between your editor and the browser or sitting there waiting for cash to rebuild or something like that. Or the time that it takes you just to pull down a local site and fix a problem if you haven't set that local site up in a while. Or even just figuring out what exactly it is you want to print to the screen. What DPM or what variable nested down deep in this big array? Do I actually want to print and see on the screen? And then especially it can help when you've broken something that you didn't think you were breaking. That's the, I fixed something over here and it broke something over there problem, right? When you have a whole test suite for all your code every time you fix something you can rerun all those assertions and make sure that you didn't break anything that you didn't expect. And so that can save you hours or even days later down the road. And even better tests that are automated can just be run alongside your editor. Every single time you make a change you add a new function, you implement a new method, right? You can run these tests over and over again just the ones for what you're working on and just get this constant and contextual feedback, right? My tests are red, my tests are green, they're red again. And I think that just kind of gives the answer to this one, right? How do I justify it to my clients? I think automated tests, especially when we're talking about PHP unit they're really for you, right? They're not something you sell your client. They're to make you a better engineer. They're to make you more reliable and more productive. And in the end that makes you more valuable. I guarantee you that if you really get good at this your code is gonna be more robust and more modular. It's gonna be easier to extend when they come to you with that new feature request. You know, you don't say to your client I'm gonna go ahead and implement this new object or I'm gonna create an interface so my code works better with other things, right? You just do it and it's something that you have to make a habit. And then how do I convince myself? And like I said, it's the hardest one to do. And I recommend if you really just wanna get started and try testing and just kinda be familiar with the ideas and the ideas of dependency injection or how to keep your functions not relying on outside stuff start with something really small, right? You don't need to start with Drupal itself. If you know a little bit of JavaScript go ahead and get Ava and just write some tests for a little toy in JavaScript. Bring it to completion and then go back and refactor it. You'll have kind of explored the problem and you'll have some ideas about how you could do it better. And I think you'll find that if it's really well tested when you go back to refactor your code you're gonna see that you're refactoring broad swaths of code much more quickly than you would before. You can just totally reimplement a function or something like that and be sure that it does at least as, functions at least as well as it did before. All right, so how do you get started? The first thing is the tooling. There's lots of it but with Drupal we've kind of settled on two different conventions. PHP unit and BeHat. PHP unit is operating at the PHP level. It doesn't need a browser and it doesn't need a browser driver and it's about testing your code in isolation. Just functions. It's not worried about the HTML that it outputs at least at those lower levels and it's a lot faster than BeHat. BeHat is the other tool. That one operates at the browser level and it can test your code kind of like a client can test your code. It's more interested in things like when I go to this page I can see that this button exists or something like that. The rest of this talk I'm actually going to focus on PHP unit and the reason I want to do that is because as a modern day software community we have to be testing our code from the basics from the absolute bottom because we can't just be testing the features that we're delivering to our clients. We also have to be testing the code that we share with each other and I think that's something that's pretty lacking right now. It's hard to find good examples of testing in all but the biggest like contrived modules, right? You can find them in views or organic groups or things like that but you don't find them in the smaller modules that you might use every day. So we all have to just kind of improve as much as we can. With Drupal and PHP unit there are kind of three conceptual levels of testing and I kind of think of it like a pyramid. At the bottom are what are called unit tests and those are about isolating very small bits of code maybe a single function and making sure that it can handle all kinds of inputs correctly. So if you're doing like an addition or a sum function you might test that it does negatives and positives negatives and negatives maybe it can handle a null value. How does it work if you pass it zero? Things like that. That's kind of your opportunity to test all the edge cases that maybe you don't really expect from your clients or expect people to enter but it makes your code like I said in the beginning a lot more robust if you can really explore all those possibilities. And then right above that in the middle layer are integration tests and those ones don't need to test all those different values like does it sum negatives and positives correctly. Just makes sure that everything works well together. So if you imagine you were making like a calculator or something and you had a sum function and a multiply and a subtract function and those had all been really thoroughly tested you don't necessarily need to know that your calculator can add positive and negatives. You just need to make sure that if you press two and two and plus and then two again it's going to actually call the add function with 22 and two, right? And then at the very highest level are what are called functional tests. Sometimes you'll see them written as system tests. And then they're at the absolute highest level. When you're doing it with in PHP unit they're actually able to like validate that maybe some HTML was put out to the screen or something like that but they don't function quite like in that you're not necessarily clicking things or going from page to page to page. But even given that this is a pyramid it's important to know that it's not just these distinct layers, right? It's kind of more like a continuum. Sometimes a test is going to fall right on the boundary and you don't need to fret kind of over about which one you're supposed to be testing. You kind of just need to know that they all exist and that you can go up and down those layers of abstraction. If you're having a really hard time testing like a hook, like entity alter or form alter, right? Maybe you're doing it at too high of a level. Maybe you should drop down and test it in like greater isolation or do it vice versa, right? So know that you can move up and down those layers of abstraction. All right, so PHP unit itself. It comes with two main things. A testing base class and a command line utility. But as with everything, Drupal has kind of added their own Drupalisms to that. Drupal has extended that base class and implemented their own. The unit test case is for those bottom most tests and then kernel tests kind of fall right in the middle and they move between kind of unit and integration tests. And then at the very top level, we have kernel test base, web test base and browser test base. And I just note that those very high level ones that can validate that HTML was not correctly. I actually see a lot of you taking photos. I definitely am gonna put this up on my slide description or session description and I'm gonna put links to all of this later but feel free to take pictures if you want to. All right, so let's actually take a deep dive here. What's the setup? If you wanna write your first unit test, how do you do that? So this is kind of like the directory structure of your first test and it's before you've even implemented any kind of source code. You have your module and we're gonna do like a hypothetical calculator here. So you have your calculator.info.yaml. That has to be there in order for a Drupal's PHP unit stuff to recognize that you actually have a testable module. You have to have that info.yaml implemented. And then within your module directory, you're gonna create a tests directory, all lowercase tests and then within that, SRC for source. And then by convention, we put unit tests in a unit directory and kernel tests in the kernel directory. And then finally within each one of those, you implement testing files that test the classes that you're implementing in your regular source directory. And there's always have to end with test.php. That kind of tells PHP unit, this is a file you're supposed to read in and actually operate on. Just for the interest and understanding, what I'm gonna do is if you guys have a question, I'm gonna just take one question on each of these actual slides and then I'll just repeat it for recording purposes. So if you guys have any questions about that, just feel free to raise your hand, okay? All right, so this is, we're actually going into the arithmetic test there. You see that in test, source, unit, arithmetic test. As with everything, we start with that PHP tag and then we actually tell it the namespace. And this is one of the gotchas that first got me when I was trying to start unit testing with Drupal. Even though we're used to putting everything in like the namespace of Drupal, my module name, and then something like controller or service or plugin, it gets flipped when you're doing tests. It starts Drupal, tests, and then your module name and then whatever's inside your source directory. So it kind of gets flipped. It's that first gotcha. And then if you're implementing one of the classes that Drupal's given us and it's already extended, you want to use that. So in this case, we're writing a unit test case, so that's what we're going to extend. And then finally, you'll want to actually use the class under test. So if you're testing an arithmetic class, you want to use that as well. And then you see that we have some comments around those. Those are optional, but they really kind of help PHP unit give you better error reporting. So you say covers default class, and then you give it the fully qualified namespace of the class that you want to test. In this case, Drupal calculator arithmetic. And finally, you give it a group and kind of by convention, that's your module name. And what that lets you do is if you're running a bunch of Drupal tests all at once, it know that you can just specify that you want only the tests in the calculator group to be run if you just want to be working or testing what you're working on at that moment. The last part of it is implementing class arithmetic test that follows that name that we used before, right? Arithmetic test dot PHP. And we extend the unit test case. Everybody good? After that, there's a function that's available in any test and that's set up. The setup allows you to set up the basics that happen with Drupal. So if you're using something at a higher level like a kernel test or a functional test, that setup function is maybe setting up a connection to the database or the fake database that you're using for those tests. But this is also a good place to create a fake node or something that you can pass to the function that you're trying to test or the method you're trying to test. And what you usually want to do is if you've got a class that you're about to test, you assign it to a property of this testing class. In this case, we're just assigning it to this arithmetic. And to follow best practices and coding standards, what you'll do is you'll also want to just declare that property just above that setup method and give it some documentation. This is the class being tested and then it's implements Drupal, calculator and an interface or something. And it's a protected property within a class. Okay, so these functions are the actual ones that run your tests. So those have to start with lower case test. If you public function test sum. And then that second part of it sum is just by convention, the name of the method that you're testing on that arithmetic class. That could really just be gobbledygook. It doesn't really matter. But by convention, it's the method name. And if you want to actually break your tests and test different parts of the function, like does it handle exceptions well or something like that, you can go ahead and extend it with an underscore and then something a little bit more descriptive. But again, everything after that test is really arbitrary. There's no official stuff there. You also want to go ahead and put at covers and sum. And that'll be the method on the class you're testing. This is something I like to do when I'm starting a test, right? I set up a number of cases that I can use to validate, to provide the input I want and then say what I expect. What that allows me to do is very quickly add new cases, new different inputs and then say exactly what I expect out of the function. And then I can just loop over those and assert the values over and over again. So here's kind of that loop, right? We go through and we loop through those cases and for each one, we get our first argument and our second argument and then we pass it to the method or arithmetic class and we get the actual value back and then you call this method that's implemented on unit test case and all of the test cases in Drupal, right? This assert equals what you expected and what you actually got. And if those two things aren't true, then what you're gonna do is PHP unit's gonna throw an error on the command line. So if we actually ran that, what we get is a failure and in this case, fatal error class and arithmetic not found. That's pretty obvious. We haven't actually implemented that class yet. But just to show you how you actually run this stuff, if you're in your web directory and that's like the Drupal base directory, what you wanna do is CD into the core directory and then from that core directory, you go up to your vendor bin and then call PHP unit and I have to go up twice because I'm using a composer-based workflow so your vendor directory might be in a different location. And then the one argument that you have to pass it is dot dot modules and then custom calculator. So the path to the module that you're under test. That makes it a lot more fast than just doing something like passing the group identifier. If you just pass the group, it will take maybe like sometimes even two minutes just to get started with your tests because it's trying to parse through all of core and contrib and your custom modules, find all the possibilities and then only test the ones in the group that you specified. So a shorthand is just to give it a directory that you wanna test. Okay, so here we're actually gonna actually go into the implementation of that arithmetic class. So we put it in the source directory, we call it arithmetic dot PHP and that kind of mirrors the name of the test as well. So it says arithmetic dot PHP and its test is arithmetic test dot PHP. So we've kind of seen this thing before, right? You start with the PHP, you give it the namespace, we notice that we don't have the test there and it's kind of flipped. And then we go ahead and implement our class and here we're doing the actual method that we wanna test, right? Given some sum, I get X plus Y. So if we were to go back to our command line, we would run that PHP unit command and we'd see we've got one test and three assertions and that's because back here, we had three different cases that we were testing. So PHP unit can tell us what we're doing there. And so if we were to add one more case, it would just bump up to four assertions. I was expecting some, go ahead. Why do you have to be in the core? That's to basically let it look at how to find the, there's some XML configuration files and so PHP unit looks for those and then also if you wanna test core as well. So you can run Drupal's test runner script from in there too and it helps it just find everything. I think you could probably do PHP unit tests on your own that don't use Drupal's standard stuff but it has coding standard and stuff like that with it. Yeah, do you guys have any questions about that whole process? Yeah, there are Drupal console ones. I don't remember them offhand. I'm not aware of any Drush ones. That's actually it. I just wanted to open it up to questions of whether you find testing useful if you're struggling with something. Okay, yeah. So the question is what's the difference between unit tests, functional tests, integration tests and all of those that go back to that slide? So unit test case starts at the very lower level. It doesn't set up a connection to a database or anything like that. So it's just about testing one single class and the code that's immediately available. So let's say you wanted to test that when you call this method, a node is saved. A unit test wouldn't be very good for that because you wouldn't know if it actually wrote the node to the database or not. So you couldn't go up to the higher level kernel test and the kernel test is able to actually install other modules and it'll set up like a SQLite database. And that's actually a really cool thing to know. So when you run kernel tests or functional tests, Drupal sets up a fake database that's used just for that one execution of your tests and uses something called SQLite, which is kind of like a mini SQL database like MySQL, but it just writes to one single file and that one single file can get just destroyed. And it's really advantageous because you can set up things over and over and over again. You don't need to say set up test nodes in your database and then actually use those in your tests. But it can actually be a little bit of a difficult thing to manage because then you also don't have that stuff in your database, right? If you're testing a method, you might also have to create nodes before every test. You can't just reuse them every time. And then web test base and browser test base, those are kind of the functional test classes in Drupal. And what they actually do, the web test base can test HTML, right? You can actually make assertions that classes exist or that a button was printed to the screen. I think you can even submit forms and it's a lot quicker than the browser test base because it doesn't actually use a browser of any kind. If you use browser test base, those are a lot higher level. They'll actually do things, try and emulate a browser. Is that into your question? Hey, the reason I've never really come around to adopting automated testing is when I started out as a developer, it was hammered into me that you don't test your own code. And all of a sudden it just came, like you started going to conventions, you just hear about automated testing and I've been to so many sessions but nobody's ever kind of talked about like why was there the shift where like not only is it okay to test your own code but you're writing your own code to test your code which might have your own bugs in it. And I just like have not been able to grasp just because of my background like that being hammered into me like I just, it fundamentally seems wrong to me. Yeah, so I think I think the biggest thing that maybe the people were talking about is that when you're writing a functional or you're writing a function and you're writing a method and you make some assumption and it's a wrong assumption, when you write that test, then your test might also bake in that assumption. And so it's difficult to test your own code in that way. But I don't think it eliminates the value of the testing because at least if you write the test first, you can start to think about the assumptions you're making and validate each one of those. It puts you in a mind state of like trying to break the code that you're about to write. You know, if you're doing it before you write the actual implementation, you can try and think of lots of edge cases and then write the test. And I think that's still a valuable experience. I think you're still gonna have the case where you miss some assumption but at least if you go back, you're already gonna have it in place. So I think it just helps with a mindset and there's still valuable stuff there. It would actually be really interesting to see like if you're doing pair programming or something, if somebody else wrote your test and then you implemented it. But a lot of us are just working on our own so I think it still provides value. Yeah, so that was a really good point, right? Once you have written the test to begin with and that assumption comes up as a bug or something like that, you just have a place to add a new test, a new assumption and it's already written out for you. You're not gonna have to start from scratch and you've written testable code because if you're just writing code and you're never testing it and no one's ever testing it, what you're gonna find is that it's all really tightly coupled and woven together and it's not testable. And so then when you do have a test case or a bug that comes up, putting that new bad assumption in or I guess it's clearing out the bad assumption, you have a framework in place and your code is already testable. So if you need to break something out and rewrite it, you're gonna be able to do it a lot better. Test when you need an entity or a node creating it programmatically or you're gonna be able to do it. Yeah, so every node, every entity type at least in core has an entity interface. So there's like node interface or term interface. And if you're not familiar with an interface, it's kind of like the difference between a node type and an actual node. The interface kind of defines the methods that are available or that must be available for some actual real thing to take its place. So you might say, if we were writing an interface for this, where is it? This class, if you see I'm implementing that interface, I might say anything that implements arithmetic interface must have a sum method and it must take two values, right? But you don't have to write the implementation. And then when you swap something out with it, you can put in a fake thing. So if you were relying on something that you could use an interface for, you could say always return two in this case. That way you could make sure your code is tested when it returns two, okay? And so those entities that you're talking about, like a node entity or a term entity, they all come with interfaces. So what you can do is within all of these classes, there's something called prophecy. So you call this prophesize and then you pass it the interface and you get back this object that implements that interface. And then you can say like when I call ID on the node or when I call get title on the node, it should return this string and then that's what you pass into the function. And so you can kind of make a fake node in place. But if you absolutely have to have a node in the database, that's where the kernel test comes in. It actually bootstraps Drupal, it'll set up that fake database and you can just say node create, pass it some values and call node save. And for the duration of that test, it'll exist in the database. Hi. Thanks, good, great talk. I find I'm sort of at the early level of writing automated tests and I find that I'm writing a lot of tautological tests, like tests that can never fail. Like I'll write a method to return an array of nodes or something. And then I'll write a test that says make sure everything in that array is of class node. And that's not unuseful because by creating the test, I've made myself throw an exception in the function so that I can test, hey, if this thing isn't there, then I should expect an exception. But at the same time, that test is basically, the chances of that regressing ever are close to zero. And I haven't been able to get to the next level of writing tests for things where there could be a logical, like there could be a change sometime that would actually affect the test and start turning it red and we'd want to catch that. So do you have advice about how to get off the shallow end and into the deep end? Yeah, so I think that's exactly my same story, right? I started there and I still sometimes get a little frustrated because I'm doing the same thing. But I think there are two strategies that I've adopted and that's really trying really hard to write the test first before you write the code because then you're not just going through line by line and saying, does this line do what I thought it did? Does this line do what I thought it did? Instead, write what you expect from the function and then implement that. And that kind of helps you avoid that. And then also if you're writing a class, try and hide a lot of those just very simple functions that do exactly like give me the first item of an array or something. That's protected methods and those don't need to be tested. So just have a simple, very simple interface like public methods that might actually fail, that might fail when the database doesn't return any results or the database connection goes away or something like that. And just test that whole class using those few public methods and then you don't need to actually test the ones that are trivial or something, right? And a lot of times the things that you want to test are when the dependencies change. So if you're imagining some test that goes and can tell you how many nodes are in the database or something, that depends on a database connection and that's something you might wanna inject. You mock it up, you implement this database or you insert this database into that class and you can then have that dependency either return no nodes, 100 nodes, 10,000 or throw an exception. And then you can handle all those cases before you actually write the code itself. Does that help? Cool. Are there cases in which you would write a test for a private or protective method? Well, so if you're actually doing this arithmetic test class and you're doing what we did in the setup function right here, you wouldn't actually be able to test those private ones. So yeah, you just couldn't do it. Would you ever go back and write tests for an existing module or do you think it would just be more work than it's worth and kind of end up with what he was talking about with writing tests that would never fail? Yeah, so I think that kind of brings us full circle to his original question, which is like write tests for, do you write tests for yourself or other people's code? You can write acceptance tests and that term has changed over time but what it used to mean is that given somebody else's code, these are the things that must be true for me to accept their updates. So if they made, like they made a breaking change, if you depended on some function in their test or you depended on some method on their class to work some way, what you can do is test the assumptions that you're making or you test how you need it to work, that way if you update the module, you can rerun those tests for it and be sure that they didn't break what you are relying on. But also it's open source so if you want to write tests, go ahead. Please do. So it sort of seems to me that Behat would be able to handle the same things as web test space or browser test space. Can you talk about when you might want to use one versus the other? Yeah, so I think web test and browser test space and I think there's actually a new one called JavaScript Functional Test Base, it's a mouthful. But you have to use those if you want to put it on Drupal.org. The test spot runs based on those classes and I don't know if it has Behat, I could be entirely wrong about that though. I have seen that a lot of people when they're up at that high level, Behat tends to be easier because it's easier to write, like I said, like a client might expect it to work. And you can point it at Drupal database that's existing, like your staging site and actually have real content that you're looking for. Whereas with the Functional Test, it's probably gonna be for more like a contrib module, you have to create the content every single time you wanna test it. So yeah, it's good for contributed stuff. So in the example you gave, you're testing like a new class that you made kind of without any context of Drupal, right? So once you start working with like your module within the context of Drupal or you have other pieces like creating a plugin for some other module or you have code in your module file, like hooks and that kind of stuff, is there like a line between what you can expect to reasonably test within the context of Drupal as well or does that bring in like Behat to the conversation instead of just PHP unit? Or like what does that look like once it gets to a real module in a project? Yeah, that's a really good question because it's something that you're gonna struggle with when you first start and it's something I struggled with. And I think that you have to be really disciplined about testing just what you're concerned about. So if your function is like a hook form alter and it's maybe making sure that a field is hidden, you have to make sure that you're only testing that you're hiding the field and not trying to test everything else. So I've kind of adopted a practice when I write hooks or I wanna test a hook. I don't test the hook itself directly. What I'll do is I'll make sure I get all my dependencies. So if I need to go to the database or something, I get those using like Drupal, colon, colon service, entity type manager or database connection, right? And then I pass it to one of those underscore functions in the method or in my module. So the ones that are just kind of for internal use and that's the function I test. That's the one that I test. Does it work how I expect or does it remove a field or anything like that? And what that lets me do is in my tests, I can inject the database and I don't have to care about the rest of Drupal. Just a little bit of stuff that I'm actually interested in. Going, going, colon. Thank you so much guys. I'm gonna be in the sprint rooms tomorrow morning. If you guys wanna actually dig into this stuff, look at like how do we test modules and stuff like that. Just come find me and I'm happy to help. Also, if you follow me on Twitter, I'm gonna be putting out a whole series where we go into the details of prophecy, how you do mocking, how you inject dependencies, stuff like that. And I'll let you know as soon as I put those out.