 Yeah, my name is Oliver Davis and this talk is TD, Test Driven Development or Test Driven Drupal, and we're talking about automated testing and test driven development today. So it just probably gets going, I guess, for me. It's about five o'clock in the afternoon here, based in the UK. My kids are home from school. We may hear kids in the background apologize in advance if that's the case, but hopefully not. The agenda to go through here is why we write tests and how to test, what types of tests do we have available to us in Drupal, how to run them. We look at an example of a module I wrote using tests and TDD, and then if we have some time, I'm aware we've got a 45-minute session, how we can go about building a module with Test Driven Development in Drupal. A little bit about me. As I said, I'm based in the UK. I'm a full stack software developer. I split my time between working on freelance projects. So in my spare time, my main day job is working for a company called Invika. We're a company. We do Drupal Development and Gento and some other things. We're based in the UK and Germany primarily. There's some links here to my website. I do blogging about Drupal and PHP and lots of other fun things. My Drupal.org handle and my Twitter username. So I'm pretty much OP Davis everywhere online. So you can find me on GitHub, Twitter, Drupal.org, et cetera with that username. I maintain quite a few Drupal modules, various other things with GitHub as well. Testing and TDD has become a really important part of that process for me. So I was talking about Overwrite and Options module. So yeah, I became a maintainer of this module in 2012. It's currently the 222nd most popular module on Drupal.org in terms of the number of sites currently using it. So it's currently just over 30,000, which is pretty awesome. There were some existing tests, which I found really useful. I came to start maintaining the module and adding patches and fixing issues. And yeah, these tests were critical for me to prevent regressions. So there's one quite large patch that has been there for some time that springs to mind. There were no tests included with the patch, but it was, it didn't apply cleanly. I had to do all this merge conflict fixing. And it was just nice to know that the existing tests still passed. And then, yeah, I ended up going back and adding tests for the new things afterwards. But just, I probably wouldn't have merged that patch if there hadn't been existing tests there already. So I'm actually looking at the wrong screen here. Let me find my slides. There we go. Okay. So this is a sort of screen chart of the module page. When I took over the module, this was 2012 or so. And you can see here that there's Drupal 5, Drupal 6, and Drupal 7 versions. Oliver, we don't see your slides. We just see you. Oh, okay. Wait a second. I'm sharing the screen, I believe. No, maybe I'm not. Apologies again. Oh, I should literally share everything. Okay, fine. Fun, fun. This is the chart of doing remote talks. This has been funny. Okay, hopefully we see slides now. But yeah, this is a screenshot of the Drupal.org page of the module. And a little bit further down here we can see there are 9,000 reported installs of this module and 25,000 downloads. These are between Drupal 5, Drupal 6, and Drupal 7 versions. So Drupal 7 was just over 2,000 usages at this point. Yeah, that's what's highlighted here. So just over 9,000 total. The newer version of this is a more recent screenshot, I think, from earlier on this year. We can see now it's 29,000, just shy of 30,000 installs of this module. So it's grown in quite a lot of times since I've been the maintainer of it. So yeah, again, testing for me has been really sort of key for all this. And you can see that the Drupal 7 versions have jumped over 20,000 when I took the screenshot back in May. And then Drupal 8, which I wrote myself is, yeah, it was over 8, almost 8,500 at this point. So it's a pretty popular module. Why write tests? The main one is to catch bugs earlier. If I'm writing tests, my local code base, I find a bug, I can fix it pretty quickly. And the time, the investment that is pretty small, it's not being shipped to production. I don't have to fix it. Nobody's seen the bug. You know, there's a big, it's called, it's inexpensive to fix it, both in terms of time and also in terms of reputation and things as well, not shipping bugs to production. Piece of mind, I don't want to break 30,000 Drupal websites. So if I'm maintaining a module or applying a fix, as long as the tests are passing, I can be pretty happy that everybody's site is still working, hopefully, touch wood. And if there's a test for something, then we're going to prevent a regression. We're going to stop that bug coming back if there's a test that shows that we fixed the bug. If we're writing test-driven development approach, then I find I actually write less code taking that approach, because I know I'm only writing enough code to make the test pass. I don't have to sort of figure out what I'm doing as I go and there's maybe some code there that doesn't actually apply, don't need that code anymore. So I find I write a lot less code doing test-driven development. And the tests also act as their own documentation. So I do this a lot with a lot of Drupal 8 projects. I go on a lot of other projects. I'll go and look at the tests and try and figure out how it's supposed to work. And also it's a Drupal call requirement. So if anything needs to go into call now, it needs to have its own tests to go along with it. This is all more important now that we can have one code base that works in multiple versions of call. So one module now can work for Drupal 8 and Drupal 9 at the same time, which has never been the case for us before. So yeah, again, just that makes it a lot more important, I think for me. So as I said, it is a requirement for Drupal call. There's a thing called the core testing gate. And this is basically what explains what it does. So anything new needs a new test and a bug fixes also needs a test to show that the bug is fixed or we need some sort of example implementation of it. So there's quite a few patches I see on core and in various modules there's a tag that says it needs tests. And that seems to be a bit of a blocker for some people, I guess. So if you want to get your things committed, make sure it has a test. And for me, with my open source maintainer hat on, I'm much more likely to review and approve patches and pull requests if there's a test that shows the thing is fixed and everything else still works. A little bit about testing in Drupal specifically. Drupal 7 had a module called Simple Test that was part of core. It was available, I think in Drupal 6 as a contrib. It was brought into Drupal 7 as a core module. It was still there in Drupal 8, but over time it's been phased out and now we use a tool called PHP unit by default, which is the de facto testing framework for PHP and it's used by Symphony and Naravell, various other projects as well. And yeah, I believe this is still the case that Simple Test was planned to be removed to Drupal 9 and since it's been moved to contrib, I did this talk before Drupal 9 was coming out, so I don't know if that has changed since the release, but it was definitely the point when I gave this talk last back in May. So how do you write tests? So our tests are PHP classes and they are PHP files with a .php extension. So this is different from Drupal 7 where they would be a .test extension, they are just .php files now. They live inside a test directory, inside your module, and then inside a source directory, so very similar to your modules, just inside a test directory. And then there's a Drupal slash tests slash module name, namespace. So if you're writing like controllers and production code or implementation code in your module, you use Drupal slash module name. So just for tests, we've got that extra tests in the binning there. And then for autoloading, our class name needs to match the file name, not to be autoloaded. And then the namespace must match the directory structure again. So these are pretty standard PSR 4 and PSR 0 autoloading things. And then as far as the tests themselves, they usually break them into three steps. So we have arrange, act, and assert. Alternatively, how they call people given when then. So the first part is setting up some things. Maybe we need to create some users or add some pages. The second part is doing some sort of action. Maybe it's going to URL or checking that a node should exist. And then finally, we're going to make some assertions. Does that node exist? Is this title visible on the page? Do we get the correct response code from our get request, that type of thing? So here's an example. A nice thing about this is sort of ties in that sort of user story type syntax I'm quite used to seeing. I see most of us are in our development jobs if you use development work. So yeah, given the about page exists, when I go to this page, I should see the text about me on the page. So yeah, this is an example. So this is our namespace for a Drupal test example. This is an example module. And this lives inside a functional directory. I group the tests by the type of tests that they are. So a functional text is a functional directory. And it just makes things a bit cleaner. We can also just say run all the functional tests in one go. Then our class, this is called example test and this extends a browser test base class that core provides us. And this is inside the Drupal test namespace. So the type of test depends on the type of class you're extending rather than which directory is in. Then inside our class, we have a method which is called test something. And there we put our actual test code. We can give them when and then steps inside there. There's also a few different ways we can write this. So you can use the typical camel case PSR compliant way. We uppercase the word something. Alternatively, we can just use test underscore something and use a snake case function name. That's fine as well. As long as it's prefixed with the word test, it doesn't matter. And some people quite like this approach because it's a bit easier to sort of read and write what the actual test is doing, particularly if they're quite long. Or we could drop the test prefix altogether and then use an annotation. So in the last example, we've got test dog block annotation. So that also makes it makes PHP unit aware of it by the annotation. So some examples of things I test on a project, not so recently now actually, creating some notes when we get data from an API, calculating attendance figures for an event, determining if the event is purchasable. This was a Drupal commerce based events management site. So there's a lot of events I think here. Propositions and coupons for new users. Someone signed up to make a member. They got two new coupons to spend on an event. We had a functionality for cloning an event. It's duplicating existing one and making some changes to it. Queuing private message requests. People could message everybody on the event. There could be hundreds of people. So we decided to queue them. Email some new memberships. They also had support ticket functionality. So if a ticket was closed and then reopened, we had a test for that too. And also some custom form validation rules. So these are just some things that I tested just on one project. And I quite like this quote. This was from the live conference a few years ago. And it says that the number one test you should write would be the thing that if you broke, you'd lose your job. Or the thing that's going to cause you the most sort of panic if it was to break. What's the most important thing? What's the crucial thing for your project that you wouldn't want to break? Typically that's to do with money. If it's giving people voucher codes or discounts or anything, that definitely needs testing. The three types of tests we have in Drupal. The thing with testing is they can be called slightly different things based on the project. But these are the Drupal technologies that we've used. So we have functional and functional JavaScripts. These are web browser feature functional tests. So these are actually going to say go to this page and use a browser or use a tool called mink to actually make requests against a page. We get the other side of the scale. We have unit testing. We also have integration testing that sets in the middle. So I'll explain a bit more about those now. Functional tests are end-to-end tests. These tests the whole part of your functionality. So go to the page. Does the page exist? Does the actual page exist in your application? So it's text testing in a browser, in a mink browser. It's actually testing your actual interface. It interacts with the database so we can use real nodes, real services, real everything, which makes everything a lot simpler. And behind the scenes it does a full Drupal installation. There's a testing profile in call that it uses. So it's quite minimal sort of full Drupal install. But these do make it a bit slower to run compared to the others. So that's something to keep in mind. As I said, there are versions with and without JavaScript. So you can pick them when you want to use based on your use case. Here's an example. Just take it from the block module. You can see it's just called block test and it extends a block test base. And we've got a test for testing the block visibility. You can see we're actually using the real convict system here and getting the values from it and actually making a quote of sort of real block in terms of it gets stored in the database and actually does get saved. And once that's being created we can make actual requests using a method called Drupal get or make actual form requests using Drupal post form or actually click a link or get user. And then once we do that for each thing we can check I can make an assertion. So essentially make a check. Does this thing show up? Does the text appear? Does this title appear or not? Is the field checked? And an example here. So these would look quite straightforward to set up. They don't require that much sort of overhead. Currently we're testing our integration test. They're a little bit lower level. We can still install modules and interact with services and our container, our database, etc. But there's no browser so we can't make actual get requests or anything. And it's an even more minimal Drupal bootstrap. So we need to do things like tell it which tables to install and which modules to install and that type of thing. Which convict to install. Because of this they're faster than the functional tests to run which is great but they do require some more setup. We do need to do some more things before we actually get it to run. So another example from the block module. We've got a setup method here. So a setup method will just run for every test. So before every test we're going to go into our container and we're going to get the theme installer and a config factory. We're going to install the block and system modules. So you need to tell it to install the system module whereas with a functional test that's sort of implied. We're extending a kernel test base class this time and there's a block creation trait that we can pull in to actually make our block. And then inside the test we're going to use a block rebuild. We're going to call on the messenger service so we can use the real messenger service in this case again and then make an assertion in this case. We've deleted all the messages so the last step is just asserting that the messages is empty. So sort of similar we need to do a little bit more setup if we go back here. We need to get things out of our container. We do need to install certain config or tell it to enable certain tables. The unit tests of the last kind and these are just testing PHP logic. There's no database, there's no browser, there's no service container, there's no anything like that at all. But it does mean that they're very fast to run but we do need to then start looking at mocking dependencies if we're going to use them because we can't make an actual request or use a real database. We need to then make a fake version essentially. One thing to keep in mind is that if we do a lot of mocking then our tests become very tightly coupled to our real code and then just making little changes and little refactors and our code can make the test break even though we haven't actually broken the code. So yeah as I said this can make it a little bit harder to refactor so I'd be wary of over mocking things. And yeah one final example again from the block module. So we're going to extend a unit test case this time and you can see but a third of the way down the screen here we've got this it says block expects. So what we're saying here is that we're expecting something to get called on block one time because of this once. We're expecting a method called access to be called and return a value, a specific value. So we're saying quite explicitly here given we've got a moped block what we expect to go in what we expect to get back out again. Yeah if we were to be very tightly coupled here we could have a problem. Yeah if we were to change the method access for example to something else our test would fail because it expects the method access to be called even though our refactor might have been completely fine. Yeah we've got similar things here again block storage expects a method to be called with this value or this array with these values in it and it will return this. So quite different from our functional test we're just saying go to a page check a response code does this text appear this is saying given this function expects this input do we get this output back out again. So let's look at an example this is another another project that I worked on actually and this was a service called Broadbean that we have to integrate with a Drupal 8 project with I don't know I hadn't heard of them before had to do with integration so I don't know whether anybody how well known they are but they're a recruitment solution the job advert solution. What would happen is the client would go in and create job adverts in their UI and they wanted these to display on the website so we needed to create nodes for these things in Drupal. We wouldn't post any applications on the site we were saying posting them to another system for them to make their applications but we needed to build a URL that linked them to the correct application to the correct page of the other application. Too many that were applications in the same sense. Jobs need to be linked to offices so they'd specify in their data coming in which office this before offices for us were I think nodes or taxonomy so we needed to make a link between the two things so we could say show us all the jobs in this office. Job length was the number of days they'd say how many days a job advert was to be displayed for. They wanted to specify the path so they specified the URL on the broadband side as to what it would be inside Drupal and then we construct the application URL and so they'd give us that we'd have a base domain you'd have then values like a role ID that we'd add as an option so that they would know which role they were applying for for and also some UTM parameters for tracking. This is how it worked so broadband was sent some XML to Drupal and then we'd build all the staff display the nodes on the Drupal side and then they'd click the application URL that we'd build and they'd go off to the the other CRM system to do their application. We added a route to Drupal 8 to accept data from the API so essentially an endpoint. They would send XML to that URL and we'd use that then to process everything and make our nodes. So we added a system user for the API role so I made a module called system user which is just a rather having just a magic user ID that was responsible for doing this. We had a module with the service that said give me the system user or system user and this was yeah this only had a role to create API data. We didn't want to give it like a full editor or administrator role for security reasons. We converted the Active 4 value from the number of days to being a timestamp because we weren't going to be able to work with a number of days on the Drupal side. We did want to have the dates the job hours get removed once the Active 4 had been passed and then yeah branch names and locations were passed as plain text because XML and we'd have to reference them via entity reference of linking a job to an office like I explained and then the URL alias that we'd wrap that to the path so that we do how to get to it. So here's an example I think this is actually the one from the website I think actually rather than one that we did. So you can see at the top we've got a command which is add or delete if I remember correctly so a few years ago and yeah some things in here like Active 4 so this one's going to be active for a year. We've got our branch name which is just a test one actually this might have been one that we did I think there's a job ID we've got the job title which would become the no title we've got some keywords so we're going to split those up and assign them to be lots of value text things same for location the role ID is quite important because that's the identifier for this unique identifier and yeah our URL alias at the bottom is what we've used for the path so they knew ahead of time which link to send people to. So yeah if there's no error we create the job node and we return a response to broad bean just a JSON response and then they'd be able to know that it was added successfully if we just throw some sort of error maybe they gives an incorrect office name for example that would throw an error we're able to save that we'd return an error code an error message so they knew what was going on types of tests so we use functional tests to make sure we had the correct job nodes with the right URL and made sure the correct response code so if something's being created which is probably the 201 response I believe and we don't end up with you know 403s for access denied or 404s for pages that are missing we had to do the application URL in the end with some javascript because we had some hosting limitations that remove all the UTM parameters so we sort of having to do this with javascript which is a I wasn't particularly keen about at the time but I was happier because once I'd written the tests for the javascript test I was happy things were working rather than there I wouldn't have been too happy but they're having the test and then I think the majority of them were kernel tests so job nodes could be added and created expired nodes were deleted after they'd expired made sure that the application URL was generated properly given all the parameters that we've had that we solved before and then needed tests just to make sure that our number of days are converted to the timestamps correctly so given we get three days and the day is now watch the timestamp B so some results we had zero bugs which was which was pretty cool there were some things that we had to sort of go back and debug afterwards but it was much easier to identify where those things were and it turned out to be on not on our side but it turned out the xml was wrong that we were passed but because we had the tests we could say as long as your xml matches this or the the value that you give us matches this then everything should work fine our tests are passing so that was great we could go back to them with some confidence which reduce our debugging time so that was great we didn't need to go go back through everything from scratch for the tooth comb just to find out that it wasn't actually that it was actually still working anyway and then any new bugs that we did find we'd add more tests for to prevent them coming back again and having any more regressions so again we didn't need to cover everything by default we're not always going to catch every bug but it is a constant iterative process we can carry on adding bugs as we find adding tests as we find more bugs so now we have lots of tests in theory and how do you run them so there is a core script inside the core scripts directory then we can run and it's just called run test sh and we can specify nothing it'll run all the tests or we can specify a module or a class and it will just run the tests for that that class or that module if we're using PHP unit which I am I think everybody is now exclusively I assume of course it is we can just run PHP unit directly itself so it's in our business our been directed vendor bin directory obviously we're going to run these locally because we wouldn't want to put PHP on production we'd specify where our PHP.unit PHP.unit.xml file lives in this case it's usually within the core directory there's a PHP.unit.xml disk which is inside the core so we just need to specify which directory it's in typically we're looking the current directory we're in but we need to there is no file there so we need to tell it where it is and then we can specify any number of arguments so this is just the path to the module we want to test so this is our examples module there's other options we can pass here as well like a filter and other other things which I think of examples four so the PHP.unit.xml file just configures PHP.unit where are our tests what do we do when a certain thing happens that type of thing and we need to run some types of tests like our browser tests and things we need some values from inside there it's ignored by git by default so our PHP.unit.xml.desk is in core we can usually copy it call it PHP.unit.xml but it automatically gets not added to our code base which is great there are some URLs and things and then that will be specific to your project so let's have a moment we just copy this and rename it and there's a couple of variables in here that we need to change get based on our project so simple test base URL is the URL that if we're going to make a request to a Drupal get request to a page what's the URL that we want to prefix that with so that might be localhost or might be mysite.ddev.site or anything the simple test DB is the database we're going to use to connect to and store our database in this could be my SQL it could be SQLite I tend to use SQLite most of the day now and then browser test output directory as if we're writing functional tests it will take screenshots of every step and put them into a file which is great and then stop on failure true is good if we're doing test treatment development and we just wanted to stop after we have a failure then we can just add this line and we don't get all the failures and then it tells with the end they were 10 failures it will just fail on the first one and stop you can fix it and go away so test room development it's just a slightly different workflow and so we start by writing our tests first which when you first begin doing this it feels quite strange like you know I want to write my code first and then write my tests afterwards but tdd suggests we write the test first and we only write enough of a test for something to fail or for the code not to compile we don't really have compiling in PHP and usually you know PHP storm will give me a little underline and say this you're missing a method or something but only you don't write all of your tests in one go you just write enough to have one failure you then write some code so if we make we're saying go to this page and we're getting a four or four that page doesn't exist for example we can write some code to make the page exist we run the test again our test is going now going to pass because our page now exists and then now everything is green everything is passing we can then do refactoring so maybe we've done you know just make that in pass maybe we just return a hard-coded string for example just to get it passing or we've done you know something just you know just to get the objective is to get the test passing as quickly as possible and then refactor once that's the case and then just keep going through that that process so again we might just be a testament to several iterations to to complete to have a passing test yeah you don't need to you don't need to write everything in advance then make everything pass that's sort of not the plan and here's a diagram to have shown that again so typically it's tests when tests are green they're passing when they're red they're failing and blue is usually refactoring so it's this constant TDD loop of failing passing refactoring and then the next go around again and add another failure and keep going so yeah it's a typically red green blue or red green red green refactor yeah and this is sort of the process i use when i was moving modules from Dupal 7 to Dupal 8 so i'd make a new branch update any tests or add maybe add some tests if they weren't there before write the code to make the test pass again this might be multiple loops around that TDD cycle that we saw and then we can refactor and then just again just keep repeating keep going around that that cycle so there's sort of two ways of we can approach TDD we can either start in outside in or inside out i tend to do the outside in approach which means i start with functional tests first and then once i've found something that i can't do with a functional test i'll drop down to another secondary loop and i'll start writing an integration test or a unit test so maybe back to the brawling example yeah if i'm writing the thing that says delete the job when the thing is expired i can write as much of the test as i can but when i need to calculate the end date i start writing the unit test at that point once that's passed i can go back up again this comes as a switching between loops the term called programming by wishful thinking so it's sort of write the code that you wish you had in your tests so even though you're writing you're maybe referencing functions and methods and classes and services and things that don't exist yet it's sort of like you don't care and you should just write the ones that you wish you had in advance try to think like what's the best way of this what's the right sort of API or the right into the right way of working with these code with this code which means the end of the you know and then you just go and write it in that way so this is why it's a lot cleaner let's say i write less code doing this because i'm only writing what i want there to be i get typically i'll write the comments first if i've got my given one then or a range act assert i will paste those in and then start filling the code and then sort of removing the comments backwards and so yeah moving the comments that's what i meant and backwards i will write the assertions first sometimes so it doesn't need to be a range act assert sometimes i will start with the assertion and i will think okay i'm doing a thing that needs a page i'm like what's my end like i wanted to be a page here that's it needs to be a response which is a 403 it's going to be accessed tonight i'll then go back okay what do i need to do to make that thing so i need to call a drupal get on a page and make it work and then okay what do i need to do in order for that to go and sew it one way backwards rather than starting at the beginning so i've learned that to work quite well i'm actually doing pretty good here the time i thought was going to take a little bit longer there we go um so we go a little bit of a demo here so we've got example of building a blog module uh so there's got some acceptance criteria so as a site visitor i want to see a list of publish articles slash blog and have those ordered by uh post date so again i see if people are working for agencies are working freelance we are probably used to seeing this sort of acceptance criteria format that's given away and then or as a as a person i can do this so i can do that so in order to achieve this there are several tasks we need to make sure that the blog page itself exists we need to then make sure that omni publish publish articles are shown so we don't want to see unpublished articles we don't want to see pages or any other content types in this in this setup and we want to ensure that articles are in the correct order as well so i'm not going to do any sort of coding what i do have is a kickup repository which is uh let's see workshop okay i can't so that was a complete it with me a second um okay so here's the example um demo so this is something that i did for um triple camp in london earlier this year i did sort of a workshop version of this and i'm doing it again for triple camp new york in the couple of weeks or next month or something let's come around pretty quick again uh we can see here i'm doing this same example everything's broken down by the number of commits i tend to do very atomic commits usually doing this type of approach we can see exactly how we're going through this constant um loop of things passing things failing going back again so yeah this is on github people go and and check it out and this is using github actions actually which could be a whole separate talk if you want to hear that words but i've got a job here that runs the tests let's make this slightly bigger let me know if you can see so this is another reason why i split tests up into their own directories in fact there's a my p2p unit config file here we can see some things so yeah these are called test tweets so i've got one called functional one called curl one called unit so these match to the types of tests that we've talked about and i can say that functional live in this directory or this path glob so any custom modules that has a test directory that has a functional directory likewise kernel and then again for unit specify my base url here and simple test db so this is my database this is using escrow live database which i quite like doing so if i go back here again to my github actions we can see this is what i'm using these are my three test types and my three test suites and i'm using symphony web server which is quite nice for these things and then yeah again if the test types is functional we're going to start a web server because we need something to make the requests against and then yeah it's going to loop over again each of the where is it these it's a loop over each of these and then specify yeah test suite in here using the matrix matrix dot test types finally so it's going to run each of those and then finally again if it's a function it's going to stop the web server so yeah any push to this repository let me just see yes any push anytime i do a push to this project it's going to trigger a new build and yeah we can see again any of these i'm going to push they've got anyone here that's using ddev and yeah we just go in and see exactly what it's doing we can see executing tests here we can see exactly what it's outputting so this is the command that it's running this text docs flag is quite nice it gives you this sort of output with rather than seeing you just see sort of dots on screen or some type of letters involved in it i quite like this this sort of output using test docs and yeah it's then it's going to run each of them and then at the end it's going to just tell us that everything's passed you have six tests and eight decisions and you know if i go in just one of these tests we'll see exactly what's doing so inside my custom module and let's just see maybe one of the blog page tests here so yeah we're extending that browser test base we do specify the default theme as of i think 8.8 i believe that's the thing we need to do which modules we're going to install so we have to make sure we need the module we're testing that's caught me out a few times and i typically like this this syntax of using the annotation and writing quite verbose test names this makes it a lot more readable at least for me and then this is the same the the test docs flag is going to use this and make a sentence out of it it's much easier to see exactly what's going on yeah we can see here it got our triple get so we're going to go to the blog page we're going to see is it does it have a an ok response or 200 response does it have a blog title and does it have the words welcome to my blog on it and again if i just show you that quickly so the time 45 minutes if we open up the blog page controller you see this text is inside inside here so this is the end the end of this obviously but yeah if you do want to go through it step by step then the commits are there and i'll just do that and then also see again it's so broken down here so actually step by step how you'd go implementing this as well i did a version of this for NWD for the northwest triple group in the UK where i actually went through some of this or maybe all of it as a sort of a demo which was quite fun so that's on my youtube channel and i'll sorry on their youtube channel which is linked to from mine as well again i'm doing this that this workshop again for a triple count new york soon so yeah definitely feel free to come on to that if you want to go through this in real time so again i did this talk a few years ago actually now for another group of triple sunset in the UK i saw this on the slack channel afterwards and this is just a screenshot of somebody running some tests and we can see that it's green and passing so yeah i made a tweet and said this this may my day afterwards so somebody you'd you know watch this talk and then gone away the next day and wrote some tests which was awesome and yeah they just said afterwards that the talk really inspired them and drove them to do testing because they're maybe a bit nervous beforehand and again so what i was saying about this piece of mine thing and they felt a lot more peace of mind from having written these tests and also found a bug which they wouldn't have had otherwise which they wouldn't have done otherwise so that was pretty awesome uh i'm writing a book or a course or something i've been not doing this on and off for quite a while but yeah if you want to go to testdriventruple.com you can sign up there and get it to my mailing list and there's also a GitHub repository around building an application out with this uh this thing um yeah this this is what's coming up next i believe we're more about that in a moment but um if you have time for questions uh this type of questions now we can reach out to me online afterwards if you want to thank you all of all um i don't there was no uh questions in the chat yet okay fine i'll save you details here so yeah if everybody wants to afterwards you can get in touch i'm on uh yeah opi davis on the Drupal Slack as well so yeah i'm on the Drupal Slack in swiss or in Drupal.org and github and all these places here's one from arduino we'll be to reach out um they ask um between running what is the difference between running the tests from a run test.sh versus calling vendor dot bin phpunit directory um i don't sure there's much for difference now um beforehand you could only run the php unit tests so you had to extend the phpunit test takes in order to make them run through phpunit uh whereas before i guess in early days of Drupal 8 we had some that we still based on simple tests which was the the legacy testing system so those you couldn't run through phpunit uh so you would have to have done that with a run test script uh i believe that Drupal ci and Drupal test bots still run using the run test script but yeah i tend just to run it through phpunit personally um because that's what i do with symphony and other projects as well if i work at anything else so pretty more familiar with the switches and things there as well i know there are things like filter so you can say filter just to give a a certain class name or things as well i don't know whether run tests supports everything that phpunit does directly okay i have used Drupal test traits um i've seen it mentioned i don't think i've used them at least not much something maybe for you to look at before i finish doing the course or at least maybe i should give them a test anyway how would you testing how do testing frameworks fit in like b-hat for example yeah so b-hat is very similar to the phpunit functional tests you so like they both make requests against a real site or at least an actual page um they do it in a slightly different way they both use the same mink driver actually so the syntax i guess is a different thing so using b-hat you're writing b-hat tests you actually write them the given when then syntax like in plain english and such and then you're writing code to make that work so you can write completely custom b-hat scenarios and then behind the scenes you're writing the this sentence equates to drupal get whatever so it's slightly different but the same thing um b-hat can be great if you're using user stories a lot maybe you've got a ba or a product owner or something who's writing these user stories or you could copy them into your b-hat and run them uh i typically will just use the phpunit ones if i can because they're already there i don't need to add another dependency into my project and yeah i would use phpunit again in a symphony project or anything as well that's what i do is b-hat and symphony as well so it depends yes b-hat and functional tests are very similar they did the same type of idea okay less if you have projects of incredibly tight time scales not only capacity for signals of output to build what is your recommendation for types of testing okay so you don't need to type to test everything and there's definitely so people will say i've got 100 test coverage or whatever i don't think that's the right goal uh if i was down for time i would definitely try and prioritize whichever is the crucial thing in that project and make sure that is definitely tested so there could be some less low level things right be not i guess not happy for them to break but i'd be less concerned if they did break you know maybe the the impact of them is going to be less um uh whereas if it's something like when someone joins up or someone leads an event we want to give them a 10 pound voucher discount code or something like if that was to be wrong and we gave them 10 discount codes for an example or we gave them one with you know a million pounds or something by default just to think of you know some slightly other examples you know if that was to break then i'd be more concerned obviously right so i guess if you have anything to do with money anything to do with user facing stuff i'm more likely to test those have had to make a choice uh that being said like when i've gone on to projects to do a lot of testing um they it takes some time maybe to get into it again if you've come from a project that's not doing it but once i get into it it actually doesn't take that much more time uh because you write in the test first i found is you sort of going like an autopilot type stage i don't need to be thinking oh what's the next thing i need to do i'm just running PHP unit and it's telling me what the next thing is to do and it's saying oh you're getting the wrong response code and i'll be okay to make the route okay but that test is failing for a different reason so i need to go back and it's sort of that automatic sort of mode which is actually quite good so in that way it actually takes sort of less i'll say less time but i get the other thing with that as well is it might take more time at the beginning but it's going to take less time when you start having to bug fix everything so you're sort of moving the time i guess but you know i have to deal with bugs and things on production i guess but yeah i've had that before i went on to one project that had zero tests and then i did it at 100 or so which was quite good yes i don't test every project there's some clients who maybe don't want to sort of pay the testing or maybe we have a client maybe on like a one-day retainer or something or a very small retainer so we can only redo so i'll say the bare minimum maybe just doing some upgrades and modules and things and maybe making very small changes so in that case it's harder to sort of go back and add tests to existing things i found so that's um that's harder but yes definitely trying if you only have so much time i'm quite advocate around testing i've gone to project managers and product owners and tried to resell the benefit of why we want to do this testing why we want continuous integration to run the tests every deploy and that type of thing i haven't had that many problems so far life yeah i i sort of yeah as far as sticking to my guns too much picking my battles i think and yeah finally i compromise less test and this feature maybe not this one even if you don't have time or budget to write unit tests at least remember to always write test or code yeah that's that's a good point always yeah maybe if you can't write the tests maybe yeah just write them in a certain way that means it would be easy to go back and write them later on yeah again i'm not talking specifically about unit testing all the time so yeah we have a couple other things as well if a client is pushing tickets with everything being an emergency yeah that happens sometimes it has to be done now how do you sell testing to the client yeah that's that's a good question there's a whole bit of selling testing is quite quite interesting and there's there's discussions around you are you a professional developer if you don't do testing that type of thing um yeah it's hard i mean like it can be hard because in a client's eyes you just you're writing more code and like almost like why oh goodness me like they're not they sort of expect you to write the first time regardless now i've actually just sometimes just written tests you know and not sort of tell people that i'm doing it but not in a sort of a way that you know it's it's about it sort of you know as a as a senior developer or a lead developer or um professional developer even you know i it's sort of part of the package in some ways like um people know that yeah like what's your pms over that does the client need to know i'm not always sure but it's definitely a discussion point then you know if it's gonna be a case of you know maybe you spend another half an hour and you write some tests you know and you could be okay that's we're not going to get a bug because x happened you know i'm sure they'd be happier but you know you're not going to give people the wrong voucher code or something you know at some point but yeah again it's one thing i'd definitely say is like don't say you know if someone's asking you for an estimate for something like don't say oh it'll take an hour and then three hours to write the tests you know because then that's going to get taken off the estimation sheet right away like again it's and as you do more td and you're always switching between testing and and tests and the implementation code the line gets fluid anyway right so you can't really say oh it's maybe it's it's not 50 50 even uh that way so yeah in the same way i wouldn't write like i could ask this once when i was doing a presentation or this for a company and you know i said like i wouldn't write bad html and then suddenly charge you x amount to write good html you know i'd just write the good one to begin with and you know it's part that just means you know test again yeah like that says yeah sell comes as part of the estimation for the work exactly and again the more you do it the quicker you get at it and you know it doesn't take as much time to do because you know you're used to it at this point i guess the problem is being pristine enough with writing tests you don't have to accurately estimate it yeah that's a good point but again like as as you write the more it does definitely get easier as it does with anything i guess really you know once once you know what you're doing with it um i'd say start small like and the thing with the functional tests i don't be small as in testing small bits of code i mean the functional tests are really easy to go in and and start adding to a project and they really quick to like they require very little setup they can be quite you know very straightforward i think some of the the ones in here are sort of a good example of that and these arguably provide the most value as well because they're actually testing real things so if we look at one of these functional tests like this test in 28 lines of code is testing that the blog page exists so we can be confident now that the blog page is never not going to be there so there's a lot more value attached to that compared to sort of does two and three equal five type of thing yeah and i'm not sure whether sneaky maybe sticky isn't the right word but yeah exactly read a bunch of tests in core i'm not sure how to go about starting a test from scratch okay yeah again i i definitely say like a lot of people when they look at testing they sort of literally think about unit testing and then they start thinking about you know all this is about mocks and etc like that can also get quite more a bit more complicated like i would say with this like this isn't too bad i think most of this is pretty not like this is right here at class so most of this should be pretty familiar to most people um and yeah again this is just the bit here that we need to to focus on so again it's just figuring out that those stages of arrange after third or given when then and you know what are the things you actually need to do there so again this is why sometimes i do it back to front and i sort of think of the outcome first i think okay i want this text to be on my page but i don't have a page yet so then i go back to this bit and then i go back to this bit so this is this is true but yeah i definitely start with these types of tests these are pretty sort of easy i think to to get going with um and arguably add the most value and then when you sort of get the end of these then look at maybe starting to do the other types of tests possibly maybe that's something i'd recommend definitely take a look at this repository if you want to if you want you know and look at this is actually broken down step by step so we can see how i'm actually doing things step by step and yeah we've got yeah add the first functional test we can see that is the whole test but let's see what if there's an actual example here blog page blog page functional test so this is the one for the actual blog so you can see that this is all done with the ttd approach so you can see that there like this one's failing and then we're adding the blog page routes and so see sort of step by step how i've done it and i've tried to be quite descriptive about the the commit messages and things to sort of explain how to do it um from there yeah again i think we can although i can turn this on yeah very quickly on my youtube there is some of those dreams that i've done some testing i definitely recommend people go in and check in that out if they want but the one i'm trying to find is public speaking where are you there is so these are all the talks i've done all the ones there's videos of and the one i'm looking for is there this one i think maybe may 2020 we're basically done this talk and then gone through that demo we had you know it's a meet-up talk we weren't quite at a time for time so i did sort of go through it or you know if you are planning on attending the the workshops of triple camp new york i'll be doing the like a four hours i shouldn't have gone through that example maybe something else a little bit different there as well so yeah i'd love to see some people there again let's see definitely done things in a better way the client cared about a piece of mind yeah i mean i guess like you're not going to go to a client and say can i use this design pattern or can i do this so there's maybe an argument of why would you ask them if you can do testing that's maybe a little bit controversial but let's see yeah i definitely it's with my like you know day job pattern it's definitely definitely happier when i've got tests to cover my work and again with my open source modular pattern i don't want to go to bed thinking have i broken 31 000 triple websites yeah and again it's not going to catch you're not going to catch every bug there's still going to be bugs probably maybe probably but the idea is don't maybe get less bugs that as we fix a bug we had a test to show the bug has been fixed and that bug can't come back again so that like you're not going to catch probably every edge case or every use case out of the box it is that continual sort of progress yes all human mistakes happen exactly exactly exactly cool okay any more questions for anybody yeah i should i should have a like a resources slide on this talk really i don't think i have one i'll find one i'll tweet the link later on but again yeah always feel free to have yeah find me on duperslack or twitter or github or ddo or anywhere else or yeah come and join the session in the york in or in the york but online for in the york that'll be awesome cool thanks for coming along um it's been sorry if the technical difficulties are you wrong i don't know what's going on there but yeah hopefully i'll be i'm gonna try to hang out a little bit this wasn't there the next arrow to maybe around the corner as well so maybe i'll submit to some of you on the networking that'll be cool as well awesome thank you very much