Hello friends, welcome back to another episode here on the channel. I hope you're all doing great and for anyone new to the channel, my name is Lee also known as Osiris. In today's episode, we are continuing on with our VGC series 11 content and we have another rental team for you all today. And this one's a real great one. This is from player Hiro. He is a Dutch VGC player. Actually, it was a tweet that I spotted from him last week where he said that he'd been able to manage getting to Masterbolt here with this special Rayquaza team. And Rayquaza, one of the restricted Pokemon that's not used very often. So definitely call my eye. Looked at the team and it looks amazing to play around with. It's got some really nice features to it and some nice options that are going to really benefit from the Rayquaza and its airlock. So I thought it would be a really good team to feature on the channel today. So Master's shout out to Hiro. Their socials are all linked down in the description if you'd like to drop them a follow. And hopefully if you do try this rental team out, I hope you have a lot of fun with it. Well, as always, we'll have a couple of games of the team and then we'll wrap up with the rental at the end. But just to kind of give a brief overview, we've got the Grimstone with the light clear, the screen support, which is going to be so imperative in this format really with Dynamax coming back. Got foul play, though, as it's kind of stab option, which is nice. It gives you a nice option against things like Shadow Rider Calyrex and Ice Rider Calyrex that we're seeing pick up quite a bit in usage. You've got the Amungus there, which gives that redirection. I think a check for Trick Room as well to a certain extent and the Cobra Berry to kind of get rid of that big flying weakness that we see from the resurgence of Max Airstream coming back. Then we've got the Star of the Shore, the Rayquaza. It's got the Life Orb to boost the attack damage there. Got Protect Hurricane Draco Meteor and Earth Power. Really great options for its Max when it does Max. You're going to have the Airstream there. You're going to have Max Wyrmwind to reduce attack power on the opposing side of the field. And then obviously the Special Defense boosts through Max Quick. And then you've got Entai, another nice option in Series 11. Had a really great time in Series 10 and that's kind of transitioning over. Got options like Sacred Fire, which can burn extreme speed bulldoze and snarl and we'll get onto the bulldoze in a moment. Got the Assault Vest there. And then Rotom Wash, a pug one that we haven't seen for such a long time and I'm so happy to see it in this team. Pairs up really nicely with something like Rayquaza as well. Can really disrupt with that airlock on teams trying to utilize the weather, just gets rid of that. And Rotom can't either take advantage of rain if it wants to or Rayquaza can get rid of things like the Sun if that is a problem for it. Got a nasty plot there. You've got a really nice option to kind of support through Grimstone screen support and then the redirection with the Amungus to help get that nasty plot up. And then Max Rotom and we know how good Rotom can be behind screens and with their redirection support anyway. And then something from older formats is Metagross. Now, I can't remember who mentioned in the comments last week on the videos, but someone did say why Metagross why is it not being played so much in Series 11 now. Dynamax is back and not seen much of it. Well, here it is. And I think it's a really good question because Metagross is still really strong in the format. It's going to have issues against things like Shadow Rider Calyrex that do cause a lot of issues with that Astral Barrage and obviously when it maxes, you need to be very careful around it. But with screen support and the right options around it, I think Metagross can still be a really nice option that comes back to linking in the entire with that bulldoze as well. It can proc the weakness policy and get Metagross set up pretty early on in the match. Ignore the speed drops through the bulldoze with its clear body ability and then get the weakness policy boost and just start throwing out really big max moves onto opposing targets. So that is the team. I'm very excited about playing it today. Big shout out again to Hyrule for the rental and for sharing it with the community. And I hope if you do try it out friends, you enjoy it. So without further ado, let's jump into Game 1 of today's episode. Okay, first up we have a Shadow Rider Calyrex, a Indidi, a Dommanitan Glaring Form, a Cinderace, a Sableye and a Landerous. So what are we looking at here? Shadow Rider Calyrex team obviously got that standard support with the Indidi, the terrain there, the redirection and then a lot of other things that you don't generally see with it, including that Glaring Dommanitan, which is more than likely. I would say Skaft in this team may not be though, may be banded because you potentially got Quash support there from the Sableye. But that does then conflict with the psychic terrain from the Indidi and opponents got to be careful with how they utilize in the Sableye in this matchup, whether or not they pair it alongside the Calyrex or if they go with the Indidi support. One thing that we have to be aware of is that we need Grimstone on this match because we need that screen support, but we don't want to kind of just allow it to get taken down. I'll take too many heavy hits early on from things like Glaring Dommanitan and Cinderace, which can hit it for pretty good damage to be honest, really useful. I think it enties a nice lead here as well. It threatens a lot of things on the opposing side of the field. We need Rayquaza in this one. It's going to be useful. And then maybe Rotom or Metagross, I'm not really keen on bringing like Rotom I think could do a job here, but we're going to need to really prioritise getting rid of the Calyrex early on because once that falls away, the rest of the team is kind of not too hard to deal with. We've got good synergies to switch around. It's the Astral Barrage threat that we have to really worry about and Grim Snarl. Going to find it difficult to be able to hit it with the redirection support. So it's going to be about trying to get rid of in duty early on or take advantage at least of the Snarl support that we got from Entai to help us to deal with it, you know. Okay, so Dommanitan, Galarian Dommanitan coming out alongside the Calyrex here. So we've got a couple of options here. We could go for a Snarl or we could go like so we could go reflect to give us a bit of a buffer against the Dommanitan here. So Entai has a bit of an easier time and then go for a Snarl. We could go for a Light Screen and then go for a Sacred Fire into... I think we've probably got Light Screen. Is the Dommanitan going to pick up the knockout though? Potentially. The other option is we just go straight for a file play into the Calyrex here. And we don't really have the switches to be honest and just like play straight, just go for a Sacred Fire because we've got the Assault Fest on the Entai here. And like I said at the very start, if we can just get rid of the Calyrex early on, this game gets a lot easier.  So we are seeing a big U-turn from that Dommanitan here, turn one. Not ideal, not ideal. And if they've got Draining Kiss on the Calyrex, that's going to make things very difficult for us, for sure, because we're not going to have that screen support. We're going to lose Grimstone. We're not going to get this file playoff into the Calyrex. So we'll see. The Calyrex hasn't protected though. So that's kind of interesting. It hasn't moved yet. So Dommanitan definitely was scarfed, but we should take this with Grimstone. We take that pretty easily with Entai as well. So yeah, we're going to get the Sacred Fire off into the Indeedy and the file play is going to be more than enough unless it's sashed into the Calyrex to pick up that knockout, but it is sashed. So that's kind of interesting. Okay. So we've got the option now where we just light screen snarl this next turn, at least we get some screen support up with before we lose Grimstone and then this snarl here going to be quite useful just to pick up the Calyrex here and just chip down that Indeedy a little bit further in this first one. So it gets around the redirection as well, which is the nice thing about Entai, especially with the Assault Vest and then that further kind of protection with the light screen support as well makes it a little bit easier to kind of manage things like Calyrex that can be a little bit more problematic, especially when they're supported by things like help and hand Indeedy, which in this case, I would have thought the help and hand would have been a bit more beneficial knowing that Entai normally carry things like snarl and the Calyrex kind of going down here without really having much too much impact in the game and the fact that the Grimstone on our side is still active. It allows us to get that, that reflect up now where we can potentially either get, I think really got to think about this as well. If the Dolemanitan comes in, I think what we would probably be better doing is getting a bulldoze off, even though it's going to damage our Grimstone, get a reflect and a bulldoze up and that slows down the Dolemanitan kind of takes away that scarf that it's got access to. So it makes it a bit easier to manage if we can get the bulldoze off, because we are pretty low health at the minute. So it depends what the Dolemanitan decides to lock in with, they tend to have things like rockslide as well, which could be a little bit awkward first to deal with for sure, because I think rockslide are probably even behind a reflect take down the Entai, but if they go for that, it does mean that Rotom can come in and if they're locked in the rockslide, we're not really too worried about that and Rotom doesn't really mind Glaring Dolemanitan too much anyway, but my opponent still got access to their Dynamax as have we, so something that we need to kind of consider as we see a brick break come out, that's a nice option there we go, get rid of that reflect there and the light screen. So that's a really nice option, but they are locked in to brick break now and so we're pretty free to bring in Rayquaza and just kind of lay some hurt down. We can go for a Max Airstream, so it kind of gives us a little bit of a buffer later on. The only thing that you'd have to worry about is their Max and the Dolemanitan here and then going after chasing down that Rayquaza. But if they do that, I think what we'll do is we go for a file play, we'll switch out because that is a definite possibility. I think they're going to pull the Dynamax trigger here. None that they're locked in to brick break, right? And they're going to have that free attack into Rayquaza and we're not going to be able to pick up a knockout onto it straight away. So I think it would make sense for me. Oh, we're not going to see that. That's interesting. Just going to go with that brick break again. Must be into the Grim Snow this time around. Is enough. Pull a trigger on that Dynamax just yet. Okay. Well, I think we'll put, did we protect? Do we protect and get the nasty plot up? Rotomarty, we just attack and hope that they're not, they're not considering this as an option. Okay. Well, I think we'll just go for a, we'll go for an Earth Power into DD and then we'll just nasty plot. I feel like Rotom can probably win us the game from this point if we get rid of the DD. And if they don't max the mana time here, well, they do. They do. And now they're withdrawing it. That's interesting. The lander is coming in. Yeah. Well, I mean, that's not too bad at all. Yeah, we can win this game with Rotom now. I don't think they've got a way to beat the Rotom. And this is the thing about Rotom, you know, it's such a good Pokemon in a format where there's, you know, there is obviously Gmax Venusaur, which is a problem. But it hangs on. That might not be actually a bad problem for us. Originally because we could go for the Airstream with, with Requestor. Or we could just, we could go Airstream. It's going to go into the DD, but it gives us a speed boost. Yeah, let's go after land rest with Airstream and then double up into it with a Hydro Pump. I think it's better at this point to Max Requestor. When we've got the room to like that, indeed he hanging on has actually done us a favor here where it went down the glaring. Don Manitun comes in, kind of complicates things a little bit for us because well, it makes it a bit more straightforward as well. But obviously without our speed boost on the Requestor, there's no way we get the jump on it with the scarf. But it's more likely that the land rest is always going to be the thing that Max is anyway. But if we can go first, which we should do with Requestor, get the speed boost and then Max Airstream plus the Hydro Pump will be enough to get the land rest. The only issue is we're going to see follow me here. So it's just whether or not a Hydro Pump plus 2 will be enough to get the land rest, which I doubt it will, to be honest. So it's still not over, but we will carry on. Just click buttons to see if we can get through this one. The Redirection, like I said, they indeed hanging on does us a favor and one respect but in another way that the Redirection is very frustrating to deal with in another regard as well. You know, just because we're not, ooh, they're going to rock fall before us. So the Quasar not Max speed in this team, which is interesting. And we're not taking that super well. So I mean, the fact that Rotom was neglected here is better. And the fact that they are a life orb as well means they haven't got assault vest. So this Hydro Pump should hit pretty hard. And with the speed boost now, we're in a good position in the next turn to pretend it depends what nature that Dom Anatan is as well on my opponent's team. You'd imagine it's adamant. Hydro Pump. Oh, it is enough. It is enough. There we go. Rotom coming back with that revenge. I don't know if it would be enough to be honest, but more than enough to take it down and we don't really have too much to worry about against the Dom Anatan here. We can protect Rayquaza if we want and just underbolt. And that should be enough to get the Dom Anatan because I think they are... Well, they have to go after the Rayquaza. And there's every chance that we could still outspeed them, but I kind of would rather not risk it this turn and just get some damage up onto it with Rotom. But like I say, I don't think they've really got a way to deal with Rotom very effectively now. After the Kalorax goes down, they kind of lose all the real kind of effectiveness to deal with Rotom because it's just that good a Pokemon. That good a Pokemon. And then about, yeah, going to be enough to get the Dom Anatan. And that is win number one for today. So we're off to a good start. And I got to say, I have had a few games with this team off-camera before I have them recording. And I love this team. I think it's such a good team. I really am enjoying it. And massive shout out to Yari on sharing this as well. So very good game to our first opponent. We'll move into game two. Okay, up next we have a Grimsknoll, Ryan Garou, Tocall, Gastrodon, Venusaur and Whimsicott team. So pretty heavy trick room looking team, but you do have that kind of fast mode in the team as well that you got to be a little bit scared of with the Tocall and Venusaur in particular. The Whimsicott can support the trick room in a certain extent. It can also set up tailwind as well for things as well. It's a kind of weird concept looking team. But the one thing I would say is that Rayquaza probably has quite a good time here. The only thing that it would really worry about with Rayquaza would be maybe the Whimsicott and the Grimsknoll with those fairy type stabs. But with screen support, we can kind of get around those. It's not terribly bad. The other thing to be a little bit careful around is obviously the trick that could come out from the Grimsknoll or the Swisheroo from the Whimsicott. And I don't know, this team feels like it's got those kind of things coming out from it. The other option is go metagross and tie, which I kind of feel like might not be a bad idea to do and have like Rayquaza Grimsknoll in the back. Yeah, I think that's probably better. Amungus could be good here as well, but I think the Torkhulk scares me off a little bit from bringing the Amungus. So I'll lock in with these. We'll see. I just feel like we want a way to try and remove the Oranguru turn one if possible. And I think anti bulldoze with Max Metagross allows us to get as much damage as possible onto the Oranguru if it does come out. Yeah, so that's ideal. But like I say, we've got to worry, got to worry a lot about the Swisheroo from that Whimsicott, which you can guarantee now is going to come out. Guarantee it's going to Swisheroo. So I think what we'll do is just to be safe because I don't want to lose my weakness policy on my Metagross. I'm going to switch into Grimsknoll, which is immune to the prankster kind of Swisheroo shenanigans. It's not going to moonblast into our Metagross slot. It's going to Swisheroo, I'm pretty sure. So we'll just try and get some damage off into the Oranguru now with a Secret Fire. If we can pick up a burn, that's pretty nice as well for us. But yeah, we want to preserve that weakness policy. I've been caught out with the Swisheroo and trick too many times now to be like, yeah, we're going to get caught with it. Although it does just protect, which is kind of interesting. So we've been baited completely as they're going to set the trick room up with the Oranguru. There's not really much we can do. We do get the burn, which is really nice. And there's the trick room set up. So I mean, what we can do is get a screen set up now, which is always going to be helpful. And another Secret Fire is going to be enough to get rid of the Oranguru in this next turn, which is exactly what we want. Yeah, we'll just light screen. And then we can reflect the next turn. If we need to, we could have Secret Fire at the Whimsicot here, but I'm not really too concerned about the Whimi. Memento. M-m-m-m-m-m-m-m-m-m-m-m-m-m-m-mento. Nice tech. Okay, there we go. It is going to fade, so it's going to go down. I do like the Memento on it. Reduces our attack and special attack two stages though. So, and Yon coming out from Oranguru, wow. Pulling out all the stops. Secret Fire minus two. Not going to be doing that much damage, not picking the knock up out. But that Oranguru is getting closer to going down. Rimsnall now subjected to that yawn so we need to Readjust this next turn which makes us a little bit more vulnerable Uh from our opponent, especially if we can see something like toko coming in and then means the double instruct but uh The one thing we could potentially do is just go for an extreme speed into a ranger Because it should still pick up the knockout and then switch into a rick waza here. Um, and then we avoid Rimsnall going to sleep And we get rid of the sun as well with rick waza so The eruption shouldn't do as much damage. Hopefully extreme speed Oh just picking up the knockout onto a ranger room. So that's good. And there's the eruption there Which we should be able to take pretty comfortably without the sun up as well. Yeah, Rick was taking that pretty well um, we still have the trick room to kind of um Deal with but at the same time We're not in too bad a position my opponent down to uh gastrodon Comes in he's gonna threaten both our pokemon really with their skull or ice beam respectively on that gastrodon um I think what we could potentially do is just slow the game down a bit at this point. Uh keep rick waza in the back go for snarl We get the sun back up by taking the airlock out of play because the sun hasn't disappeared So this is how our airlock works. It just negates the effects of the sun. So the sun's still in effect. Um It's not overwritten like it would be if the the rain or the sound of the hail came in It's still in effect. It's just as long as airlocks out in the field. It has no additional effects on anything so The sun coming back out it will boost tokens damage output here, but at the same time it reduces the um the attack power of something like scald or Max guys are that's probably coming out from this gastrodon. It could be max hail storm Even let's see max quake is more likely. I would imagine but are we are going to be able to take this Then tie a soul fest The light screen up I would say so I would say so as part of the doubling into entire thing um Okay, well we take that pretty well Oh max hail storm chasing down that rick waza. Okay, that's all right Get that snarl off And then we're sitting in a much better position And the sun does disappear Yeah, so that's that's what we want Max quakes are what's really a little bit Annoying to deal with But the special attack drops are always useful now. We've got to be careful about what we switch in where now um Might be worth just keeping what we've got in the field Out now while we just kind of stall out these last trick room turns. We've got one more turn. Yeah, so there's not really much point of Getting anything in now Reflect isn't really needed um I think we just file play into the gastrodon just to get damage off into it to be honest because Um at this point the toggle is not really too much of an issue Especially something that requires I can deal with it pretty pretty easy um I mean the option there could have been like rick waza for the entire could have been a really nice switch in there and max who use Going to be into the the grim snarl But we'll be able to negate that special attack boost With another snarl and then file play As the trick room ends and we'll be able to get another snarl on their final turn of max Which just sets up like rick waza and met across the kind of coming and closes one up for us. So That is not too bad at all Although the file play is not really doing too much that gastrodon looks so sad there big big dynamax gastrodon looking so So sad so sad um Wonder what that is that last poke. No, they've got whimsy. They had whimsy cut didn't they they didn't bring it restricted to this one Which is kind of interesting. They have a restricted. Let me just check this Did we not notice they had it no restricted. Okay I didn't even notice in team preview. I've just noticed now literally just notice now My god, what is wrong? What is wrong? They may max use again But the battle is cancelled and that is two games with rick waza We didn't really get to see the rick waza in this last one But we got two wins. So that's all that matters and we got to see the team kind of function well Which is always enjoyable. Um, so I hope you have enjoyed this episode good game to our opponent fair play for not bringing a restricted to a restricted ladder Um, it's brave But we will hop over now and remind you all of today's rental code friends Okay friends here is today's rental code big shout out to yarrow once again for providing us with the team for today's episode And I hope if you do try it out you have a lot of fun with it and definitely check out their socials Which are linked down in the description below and the rick waza It's probably one of my most fun series 11 teams that we've played so far I know only two weeks into it, but I'm including that in series eight as well I really love this team a lot. Um, and I do feel like I'm going to probably play a lot more on the ladder going forward Because it is just that much fun and it's got some really nice kind of build text to it So if you do have it a go with it I like I say you're going to have a really good time with it The rautom is a really nice option as well It kind of gives you a lot of flexibility in the team that I think is missing from some series 11 teams So have fun with it. There is the rental. We'll wrap up their friends. Have a great rest of your day Whatever you're up to and I will see you all in front of the episode very soon on the channel So until then friends take care of yourselves and bye. Bye


Okay, uh, there's a lot of pathways over here, man. I feel like this, oh my god, there's somebody, no! Hey guys, Realistic Gaming here. Today we're gonna be playing the True Backrooms in Roblox. Okay, so let's see what this is about. Let's read the description. It says, You wake up one day in an unfamiliar environment. Your goal is simple. You must find, exit, and escape. Alright, so that's pretty simple and straightforward. So it seems like we're in this giant room with like endless rooms or something like that. I don't know, man, so let's join up on this. Here we are, the True Backrooms. Oh god, okay, so, uh, this place looks weird right off the bat. Okay, so it seems like there's just rooms everywhere. Yo, what's up, man? Look at this dude, he's just running up on me like that.  Alright, so we're in here, wherever we are in the backrooms, and it says, Find the exit. Okay, so it's like a painting of a door, fire exit. Okay, so I assume that's how the exit looks. That is a pretty nice visual picture of the exit. And it's timing us. We have 30, wait, oh, I guess it's timing us to see how long we take to find the exit. Okay, so let's head on out of here and begin this adventure of finding the door in like this endless maze. Okay, where are we going, guys? Yo, what's up, squad? We're here with the squad right now. And one thing I don't like about this is I don't think you can chat in here, so that's not cool at all. Yo, what's up, guys? Is that like a camera, like a megaphone or speaker? I don't know what that is, but let's get out of here, let's continue. Okay, where are we going? Oh my god, there's a lot of people here. Okay, okay, let's go towards the dark. We're in the dark side now, you guys. Welcome to the dark side. Okay, so let's go down here. Wait, should we go over there? I don't know where I'm going. Okay, let's show me the way, bald people. Even though we're all bald, I see another shadowy hallway. Is this the correct way? I think we are going the right way. Okay, let's go over. Oh, what is this? The surveillance room or something? Oh my god, so they've been spying on us this whole time? Major creepers, man. Okay, so what is this? It's like a list. Can't even read that thing. Oh, the exit's over here. Everybody, let's go to freedom. Two minutes and 28 seconds. That wasn't so bad. Teleporting to the next stage in 10 seconds, but how many stages are there? Okay, whatever, stage one. Okay, so I guess we were on stage zero and now we're on stage one. Okay, yeah, what's up guys? Okay, so now we're out here in the second level and now we have flashlights, but it's darker now. Like it's entirely dark this time. All right, so should we go straight? Wait, is that a dead end already? Boy, that is a dead end. Oh my god, okay, we can't go straight. So it's either left or right. Everybody's going left, so let's just stick with the crowd and see where we are.  That is totally not scary. They look like mannequins chasing me, man. I hear like a roar. That's a dead end over here. No, go over here, guys. Dude, I hear like a thud or something, like footsteps. Okay, I don't think we're here alone, you guys. It's not good. What's up Tony Stark? Okay, there's a lot of pathways over here, man. I feel like this...  Dude, it's like a dark figure. Why is everybody running this way? Oh my god, okay, so there's definitely somebody out here killing people, but just not good at all. Oh no, dude, where is he at? Okay, he's super slow, so we should be fine. Dude, it's another dead end. Turn around. Oh my god, I gotta wait for me. Okay, I thought there's more than one. You gotta be kidding me. Okay, so this has to be the correct way if there's monsters over here. Oh my god, take one for the team, man. There you go. Distract them. That's what I'm talking about. Okay, down there or this way. Okay, so definitely this is going to be way much harder than the first level. I'm going to go insane just being here, man. Wait, where's everybody at? How do I lose all the squad, man? Oh, somebody just died. Dude, he just killed two people down there. Okay, I'm out of here, man. Let's go, go, go. Oh my god, this place is way much worse than the first part. There are so many like turns. Okay, there's nothing here. Goodbye. Hopefully this is the right way, man. I don't know where we're going. We're just turning corners and see what awaits us. Dude, we just went, dude, we're just going a giant circle. Wait, no, we didn't. I think we did. I don't know, man. Let's just keep going. Okay, nothing here. Kind of skeptical about this place. I'm checking every corner.  It's like a two-way mirror, I think. Oh my god, the guy's right there. Dude, that dude just on the exit. Let's go. That's what I'm talking about. Oh, my boy. Oh, you're just supposed to fall down there, right? Oh my god, that took us three minutes. It took us only about a minute longer than the first level. That wasn't so bad, man. Dude, we're pros at this. We're getting the hang of this, even though I'm just going anywhere randomly. I mean, this game is just more of like, just go with your gut type of thing. Oh my god, is this like a solo stage? Stops them. Long. Wait, what? Long beam? They are unpredictable. Okay, what is that supposed to be? Guys, where's everybody at? Okay, so now we're alone in this one, and this one seems a little more creepier. Oh god, okay, just take deep breaths, man. We're here alone. We got this. I know something's going to jump scare us or something, man. Oh my god, this is so creepy down here. Okay, where do we go? Should we keep going? I heard something. Okay, let's just keep going straight. Oh, you can sprint in this so nice while barely. Hello, anybody here? This is so creepy. Okay, there's nothing here. It's a dead end. So let's go back this way. I keep hearing like thuds. Maybe it's just a sewer pipeline. No, you see, I hear it again. Oh god, this is scary. I hear like a buzz. Okay, let's go down here. You are tired. Yeah, I'm tired of running into walls all the time. Wait, what is this? Oh, we just knocked it down. Okay, so it seems like there's somebody else lurking here. They're being a creeper. And what is all this stuff? My god, okay, there's some like computers and stuff. Oh my god, what is going on in this place? Okay, let's get out. Oh look, there's a note. It says I'm sorry. What? Let's get out of here. Okay, so we have to go back this way.  But now we have to go all the way back to the start because all these spots are dead ends. Okay, why am I tired? Come on. And you're like not be tired anymore? Thank you. Okay, what is this? Is this safe down here? No. Oh my god, why is it so dark? Okay, don't tell me. Please don't be a dead end. Okay, we're getting closer to whatever that noise is. Please don't be a dead end, man. I've been walking down this tunnel for like 30 years already. Oh my god, he's right there. Dude, okay, this might be the correct way because he's coming. He popped out over here.  And like heavy breathing. Yo, this is not cool at all anymore. Okay, can we keep going down this way? Well, I mean, of course we can, but dude, that is scary. What is that?  You gotta be kidding me. Okay, so I think I'm gonna be trapped in here for like ever.  That does not sound pleasant at all. Not another dead end. You gotta be kidding me. I think, oh no, he's right there. Did he disappear?  Okay, so this guy is definitely on our tail. Please don't let this be another dead end, man. Thank you. It's not. My god, where are we going? I see the exit, but there's a creepy guy over there and he's walking towards us. No, get away. Is he really coming to at us? I think he is.  Okay, let's just run for it. Make a run for it. Go, go, go. Where do you stop? Okay, so now he's tired. Come on. This is a wrong time to be tired right now. No, you better not. Oh, I swear we made it. Nice. Okay, so that was a little longer. This one took us four minutes. So like our time, it keeps getting longer by a minute every time. Finish zone, you finish the true backwards for now. For now, are you kidding me? More stages will be added soon. This game is not complete. I wonder if this is any place that has any secrets. Wow. I assume it does have secrets because I mean, why wouldn't it? Because it is like the completion level, but I guess let's take a look around, a quick look around to see if we see anything around here. Okay, hi. Hey, does this wall see weird to anyone else? Okay, let's go. Oh my God. Okay, cool. We found like a secret room. The crew. Cool, man. Okay, so there's YouTubers right there. I guess those are like the devs or something. All right, you guys. Well, thank you guys for watching. Thank you guys for the amazing support. If you guys enjoyed the video, make sure to slap the like button. If you're new to the channel, make sure to subscribe and hit that notification bell. And I will see you guys in the next one. Bye.


Hello everybody. Thank you for coming to my talk on two of my favourite subjects and automated testing, testing and development. My name is Oliver Davies, OP Davies everywhere pretty much online including Drupal.org. The slides are already online if you want to look at them as we go or later on the second half is quite code heavy so it's there if you want to look at it later on. I'm a software developer, I'm a full stack development consultant and I'm an open source maintainer so I develop and I consult on a lot of Drupal projects for clients. My day job was using Drupal and I maintain quite a few Drupal modules and themes so I've got quite an interesting perspective on this coming from a few different angles. This is a screenshot of quite an old tweet. This is from Tim Millwood, this is February 2012 which seems like what it is a long time ago. I realised the other day and this says anybody want to maintain or comment in this module could override node options. I said yes and then in 2012 I became a maintainer of this module. So this is how the project page looked back then, the UC stats looked like. It was used on just over 9,000 sites back then. There were Drupal 5, 6 and 7 versions I believe and then currently looking at the page a couple of days ago it's currently used on just over 38,000 websites which is quite a lot of websites. A lot of them are Drupal 8 and Drupal 9 but also if you look at the overall installations across all the projects it's going on 173 which out of about 50,000 modules and that at all. So there were some existing tests. I took over this module and those were really critical to prevent regressions as I'm doing new releases and bug fixes and refactors of this module. So why write tests? Peace of mind I don't want to break 38,000 websites when I do an update. I'm sure you guys don't want that either. Also I don't want to prevent regressions either in the module or in client code of my own projects as well. I want to be able to catch bugs earlier. So if I can find a bug in a test and fix it there rather than it going on to production and then having a client find it or have a failure of a CI pipeline or something I want to be able to fix it right there and then test it and allow me to do that. Usually you're doing TDD, you write less code. You only write enough code to make your test pass. Tests are there to tell you when to stop. If you don't have tests and you're not doing TDD then you'll just carry on writing code and you'll end up with a lot of code you maybe don't need. It acts as documentation. So normal documentation in markdown files or Word documents or whatever can become out of date and be stale. Tests can't do that because you run them very, very regularly and if something comes out of date then the test will fail. The Drupal core requirement, so if you want to contribute something to Drupal core you need to have a test with it and this is just more important as Drupal core is speeding up as we know we get new releases now every big releases every 12 months. Modules support multiple versions. The current overriding options module supports 8, 9 and 10 in the same version and this is just going to become even more important as we hear about automatic updates and core updating by itself. So a little bit of history of testing in Drupal. In Drupal 7 we had a simple test module that was included as part of core. When Drupal 8 started with the added PHP unit which is really the de facto testing framework in PHP still is. We also passed these out which is very popular but I still think PHP unit is still the default and the de facto version. It then became the default for us in Drupal 8 and 9 and then in 9 a simple test is gone. It's in contrib. You can still install it if you want to but it's more there's a transitional thing to move to PHP unit. So how do you write PHP unit tests for Drupal? Everything is a test, each test is a test class. They also have a PHP dot PHP extension. You have tests per module so for each module has its own test directory. You're not writing tests at a project at an application level. You're writing them per module. There's a separate Drupal slash tests namespace. So if you're used to using some Drupal slash your module name, you'll do the same just with tests before it. And then because of PSR for water loading, the class name must match par name, the namespace must match your directory structure and one test class per feature. So very similar to writing controllers and other classes that use PSR4. So three parts to a test. We have a range, act to search. So first of all we set up what we need to make our test work. We then perform some sort of action and then we make assertions based on it. So given we've got these things, this thing happened, does our site now look like this. You can also mirror this to given when then. People used to seeing some user stories and said this criteria where you've got given I'm logged into this user when I do this thing then that should happen. Some things to test. Here's some examples from projects I've worked on before. Tracing nodes with data from an API. Talk more about that in a minute. Calculating attendance figures from an event. We built an e-commerce site where the product was the event and people attended by buying a place on it. So we calculated attendees by who bought the product. Determining if an event is purchasable. Same project with date ranges and if it was full and things you might not always be able to purchase a place on an event. Promotions and coupons for new users.  You want to clone events. So this is a very event-driven project actually. We're to clone events so we want to have one event and then we want to duplicate it again the next month or the next year or something. I want to send private messages to attendees. So we did that using a private message module. So we wanted to queue them because some of these events had a lot of attendees on them. So we wanted to queue them so we don't overload our web server and send 500 e-prior messages in one go. This is another old tweet. This is from Matt Stauffer, or the tweet of Matt Stauffer's quote, which I liked. Test the thing that you lose your job before it breaks. So I want to have confidence that if I'm finishing the end of the day or I'm going on leave for a week, or I'm finishing a project, or I'm pushing an overnight options update, I don't want to worry about everything breaking, or comes down to this sort of confidence and being able to be happy that things and common work is expected. So what does a test look like? As you said it's a PHP class because we're doing a PHP test. It's in our Drupal test namespace. We're going to use in this case a browser test base class. A number of these different types of tests we can use in Drupal, and there's various base classes we can extend. So this one's browser test base. We'll talk more about that in a minute. And then we've got a test method. So it's a function or a method within our class that we can do. So this one just has test something, and then we're going to make an assertion that false is true, which is obviously going to fail. So it breaks into our normal... That's how you'd write a normal PHP class in a control.org. Not too simple. There's different ways of writing these test methods. You could use the camel case, the suggested way of... Everything's to start with the word test. So we can test something as in uppercase s something. Convention is to use snake cases for camel names. Snake cases for test names. Snake case for test names just because it's more readable. I quite like this convention. I use it quite a lot. And then you can also drop the test prefix to get completely and use an annotation, so at test comment. So usually I'll use the third of these options, but you'll see different variations of it in different projects. As I said, there's different types of tests. So it's not just unit tests that are available to us, which is common. So I think people think it's just unit testing. It's not. We have these four different types of Drupal that we can use. Functional tests, which are also called web test browser tests, feature tests, that actually make tests against endpoints and check in the results and things. So make sure you're actually looking at the responses you're getting from your code. You're going to run kernel tests, which is also integration level tests, and then unit tests, which is what we'd expect for testing logic and things. So function test, test end-to-end functionality. So you can say go to this page, do we get the right response code, do we have the right text return mark, does this match the HTML that we expect to get back? So it's very user interface sort of level testing, which interacts with our database. So we're not mocking anything in this type. We're actually using real database. It's going to be like a MySQL database, a SQL-like database that's separate to your normal database. So you don't have to worry about your things being deleted when you do a test. It's going to complete Drupal installation behind the scenes. You can test it in profile. So your data is safe. Because they're doing all this behind the scenes, they're a bit slower to run, because they're having to do all this setup on this bootstrapping behind the scenes. There's variations we're running them with or without JavaScript.  So we can test modules. We can test our service container. We can make sure our service is run properly. We can do things against an actual database. So we're still using a real database for integration tests, for kernel tests. It's still doing a Drupal bootstrap, but it's doing a more minimal version of it. So we've got a bit more setup to do, just to get them to run, but they are faster, because it's going to do less for the start of the box. The unit testing. This is very PHP logic level testing. This is a typical calculator thing. I put 2 plus 2 equals 4, that type of logic. So not testing service container or databases. We're testing very small, isolated bits of logic. These are super fast to run, because they're just testing logic things. They're not retouching. So we can't do a thing with a database. If you're going to need a database, you need to mock everything. So you're saying this is a fake version of this thing that we need to use. On the downside, they can become quite tightly coupled, because you're mocking everything. Sometimes you can just end up testing your mocks. I've done this before, and I've written the whole thing, and then gone, I'm just testing what that mock does. I'm not actually getting any value from this test at all. If you write very tightly coupled tests, they can be difficult to refactor. If you write tests that say, this thing gets called three times and returns this. If you refactor that later on, it might not return it three times, or it might not get called three times anymore. It still works, but your test is going to fail, because you've been very, very specific on how it works. So how do you run the test? There is a run test.sh script in call. I rarely ever really use it, but it's there. So it's sort of a wrapper around some of the underlying plans that we can run. It's a PHP file, even though it's a .sh file, so you can run it with PHP filing. There are different flags that we can pass to it, like all if you want to run all your tests. You might want to run the test in a specific module or in a certain class. We can specify that as part of that. This is one I'm doing in one of my Docker examples that are on GitHub, specifying you want to run tests within the example module. This is SQL Lite database. So we're going to put the SQL Lite database in this file, so that's where it can run quickly. And then because it's Docker-based environment, you can also tell it where our web server is. So we can make requests and then look at them and get it back. Because it's on Docker, it's not all in localhost. They're all named differently based on the service name. So this one's called web. That's the other test will fail. So here's an example. If I run that, this is what we'd see. We can just run. This is running against the example module project. So we're going to run this example page test. We can see when it ran. Let me get a little summary at the end. So we can see what tests it ran and very importantly whether they failed or not. So this one passes. I hope it would. Usually I'll just run the page per unit executable itself. So I need to specify still the simple test base URL variable that tells it where our site is. So I need to set that first and then I can call the vendor bin page P unit executable. There's a page P unit XML filing call in the call folder. So I do specify dash C, which just tells it where our configuration file is and then any pass the test if you want to run. And we see something similar. You can see what it's run.  If it fails, you get an F. If it's an area, you get an E. If it passes, you get a dot. It's not just things on the screen. And again, we'll see how many tests it ran and how many paths and how many failed. So we can create our own page P unit XML file. As I've said, there is one in call that we can use. And it's just a file that configures how a page P unit runs. So we can copy the one out of call. We've got an XML.dist file which is our default version, our standard version. And we can then copy it to make changes to it as we want to. So this is a very Drupal core focused slide. If I was doing this on actuals of application or for a project, I can make my own version of this file in the root of the project and make my changes to it there. But this is a very core example. So things we want to change are base URL. Again, so it might be local host. On a Docker example, it might be web or whatever your container is named. We need to give it our database. So it could be my SQL database. It could be the same database as your application is using with a different prefix. I like to use an SQLI database. And then you just create it, populate it, throw it away afterwards. And if you're doing functional tests, you can have it save the code and screen, sorry, the screenshots of what did and save them in a file in a directory called browser test output directory. So you can actually go back and see them afterwards, which is really helpful for debugging. Something else I use quite a lot is stop on failure. I set that to true. So whenever a test fails, it just stops. So rather than running all the rest of the tests, I just want to know there in there that something failed. So an example. So on a project a few years ago, we had to do an integration with this service called Ruby. So recruitment management solution, people post job address and things on it. One of the things the client wanted us to do was have those job ads appear on the website as well as the other places they had them. So our spec was they wanted to create jobs in their UI and we wanted them to appear in Drupal on the website. The application URL is something that came into us. They would apply to another system, sort of the middle part of this equation. We take the domain, we take the role ID that they'd set and then there's some other parameters and things like where the job would come from etc. Jobs were linked to offices so they passed to tell us which office it was located in as well and there was a certain number of days that this job was active for. They also wanted to specify the path so it would be like mysite.com slash something and they passed it to that as well. So this is how it looked. We had the broadband stuff on the left. They send us an X and L we made an endpoint, a web again point available and they would publish the data there in Drupal. We would do our stuff there, create the node, people would click it, they would then see the application URL, click it, make their application in the screen. So we made a route that allowed us to accept data from the XML. We added a system user, so just a Drupal user that only had access to do this one thing, just to keep things less insecure. So this is the amount of time and the number of days it had to be visible for and we got the branch name, the locations, the attendance, what is it, plain text and XML and we would link them to entity reference because we had offices as a content type as well. And then the URA says that they'd pass us so we'd map that to the path. So this is what the data came in looked like in a PHP arrays. We got it from XML, we made it into a PHP array first of all. We can see we got a command first of all adding or deleting the job address. They give us something like a username and a password. The number of days, some details, the details would become the body, the job title becomes a no title, etc. Yeah, and if there was no error, we created the job and gave our 200 okay response back to probing so they knew it worked okay. If there was an error with some description, then we returned an error code and the method we gave them that. So they were able to give some feedback to the user at the end as well. So how did we use different types of tests for this? Functional tests first of all. So we made sure that our job nodes were created and created with the right URL. We got the correct response code back from them. We then used some JavaScript tests and the application URL we had to update the JavaScript because reasons. There was something to do with UTM parameters I think that they didn't work locally but as soon as you put them like UTM source it didn't work so we had to end up having to do with JavaScript. Actually it wasn't the best solution but when I had the tests I was quite happy that it worked so that was a nice benefit. We used kernel tests to make sure that the job nodes added and deleted as expected. Once they expired they deleted and then also made sure that our application URL was generated correctly based from the number of pieces we were to make it from. We then used some unit tests to make sure the number of days we converted to timestamps correctly because we were using the timestamps. Some results we had no bugs everything worked as expected it was right. There was some debugging time so there were some queries that it did stop working at one point but it's easy for us to go well as long as you're sending us the data in this format it will work because we've got tests and the tests are passing. So if you're not sending us the data in the format it's going to break potentially but it's actually really quick for us to debug this because it rather has to go through the whole module and then debugging everything we could just lead on our tests and say everything from outside is still working. So again, send us data in this format please. So test-driven development so we're really sure we're automated testing as it's on this thing. TDD is on a separate thing. It's just the workflow of writing a failing test first so we start with the test this can be quite scary to begin with it was for me, I'm sure it is for everybody. You want to write the code first because that's what you used to doing and then write the test afterwards. There's advantages to that. With TDD you write the failing test first and you want to see it fail. Then you write enough code to test a pass but you want to do any refactoring that you want to do whilst things are passing and then you just go through that cycle again so you maybe add some more assertions or maybe we want to do the next test afterwards. We call red, green refactor so red is when things are failing green is when they're passing red, green, blue unfortunately my slides are not going to be red and green unfortunately. It's also the approach I use when I support modules to duplicate including the node option module so I used to make a branch and then move the test across first look at the failures make them pass and that's how I did that which workflow give me a reading out test so I like to write tests outside in so I can start with the top level start with functional tests see how those work first they're probably the easiest to set it up and probably the most valuable does our endpoint work do we get the right response code that we need and then when I need to I'll drop down the level I'll do integration tests or unit tests if there's something that doesn't work in a browser it depends based on what you're testing and what you need I like to think of a program I wish for thinking you write the code you wish you had and then the test will tell you why it doesn't work and then you write a bit of it to work and then over time your test will be green then you know it works in my tests I like to write comments first usually so there's some spec things out usually again in that given when then or arrange a certain phase and then fill the code in afterwards excuse me I'll just keep me on track and usually I like to write the solutions first I'll start with the bottom of the test then it will work my way up I'll say that I expect there seems to be one and it will go well you don't have a variable called articles I'll write the variable articles and work it my way up it's the opposite of the inside out testing you start from unit tests to it's way up but I prefer this approach here's a project I've been working on at the moment this is the counter number of tests I've got so another thing how much is if you put them in organise them in the correct directories you can then call them using different test suites so I can just say run the functional tests run the kernel tests that's what they do in this project and I've got a count of the numbers and things that we've got right on this project I've got 57 functional tests 180 assertions in there I've got 38 kernel tests and then 5 unit tests and the other approach we get is a testing trophy so it's wider the bottom and works its way up in that sort of pyramid sort of fashion I'm doing the opposite so I've got more tests on the top when working my way down I run these in a CI pipeline whenever you push using GitHub Actions and they run in about 2 to 3 minutes so we've got a demo I'm not going to cover it all unfortunately just because of time it's a short and simplified example I've done a longer version of this before I've probably used something and I've probably used views for it in an actual real situation I just can't type and do this with views but for this example I'm going to we'll go down this with the custom code root you can see how this works so if you think I'll accept this criteria as a visitor I want to see a list of articles of blog posts at a page and I want to see them sorted by the post date the most recent blog post at the top working on my way down so my tasks are I want to make sure that the blog page exists I want to make sure that only published articles are shown and I want to ensure that they're shown in the correct order so we can start by scaffolding out the test so this is a start we'll do this outside in we'll start with the functional feature test first so we'll just scaffold that out this is in the functional namespace again I like to group the functional tests everything grouped first of all by type and then if it's like sub-directories I'll usually mirror the sub-directories structure so we'll do that as well there's a couple of default things we need to pass one is the default theme I think there's a Drupal 9 I'm thinking we need to start to find the default theme as well I've had test the fail because you changed the theme and the markup is slightly different Stark seems to be a good starting place for me anyway and then here this is part of my scaffolding I've got an empty modules array we'll see that in a minute and then we can write a test so I can say that we expect or it loaves the block page we'll use that sort of snake case type name with annotation I think it's fine over test code and I changed my phpcs file to say it's fine on tests so we're going to use this functional group of get so that's going to go to the page or to the URL that we've specified get the actual request back and then we can do assertions against it so we can say that first of all we want it to return a 200 response so it's a TDD so we haven't written it yet so what's going to happen so this is an example of what we'll see we've got a big E at the top so we've got an error because the page doesn't exist about half way down the slide here we can see current response status is 44 as in the block page doesn't exist so we haven't created it yet but we're saying we want to get a 200 response code so we want the page to exist again we usually get this little stack trace of what's happened, what's called what and then at the bottom we get the number of tests, the number of assertions there's all the summary at the bottom and errors in capital letters which is nice so again usually I'd use use for this but for this example we'll do it in a custom coding way we'll make a reading file and we'll call this blog.page and we'll say available at this path slash blog which matches our criteria we'll specify the controller we want to use this will be in our DrupalCon module in the controller directory and we'll call it blog page controller I'm not specifying the method names we'll use an invocable controller it's just my preference we'll give it a title and then some requirements so we need to be able to access content to see this page so we've run it again and maybe we think now that's going to work or at least we're going to get a different message or a different error but we don't in our test we don't know that the node module sorry that the spoilers, we did it at the DrupalCon module our module is not enabled so in our modules directory we just say we're going to enable the DrupalCon module if you think about your Drupal websites and the whole application and worry about saying the word project but I think project and Drupal.org sense is a module or a theme so if you think about uploading it to Drupal.org then it's not going to know which modules and things you've got on your project so we need to specify them so once you've done that we say enable the DrupalCon module that we're making our error is going to change so we're making progress this is this TDD workflow that you have a failing test you then make the error change then you keep going so now our response code has changed so now we're getting a 4 or 3 we've gone from a 4 or 4 to a 4 or 3 we're still wrong so we still get the failure so we need to enable the node module in this case and let's just see here because of this permit if I go back up the slides we've got the requirements permission the factors content which is given by the node module so we need to enable the node module so once again our status code has changed so we're now getting a 500 error code so something's broken but at least the page exists now so we need a controller we've told it that you need to go to this controller and then go to the invocable class and then that's what we're going to use we haven't created it yet again because we're doing TDD so we haven't created our controller so the next step is to make our controller and we're going to make the smallest controller possible to get our test to pass so let's make invocable so we use the global underscore underscore invoke and we don't need to return an array because we could have turned a render array so we'll just return back an empty array that's enough to get our test to pass so we're getting our correct response code now so we're getting our 200 so that's a good first step I think so the next part is we are the look to refactor it's not really a thing to refactor at the moment but we'll keep adding more assertions so we know we're getting the right code what we don't know yet is whether we're getting the right page the right page title or the right text on the page this will fail and we can make some changes to our block but it's a controller to make this work so we're going to get it so we're going to return back an empty array we'll say hash markup and we'll return back the text that we want make that work and the title will be set in the root style between and again our test passes so again imagine this is green usually this will be green in your terminal output but not in slides so we know the page works but now we need to make sure we've got content on it so I'm going to use a repository pattern use the repository pattern for this and then an entity a kernel test base so this is a kernel test integration test but again there's a number of different classes that we can use so entity kernel test base extends normal kernel test base I found for a long time when I was writing on this particular project anyway kernel test base I'd have to do the same set of steps every time and then I found the entity kernel test base that did it all for me which made my test a lot smaller so I'm going to say so we're going to test a classical article repository again the convention is it's the class you're testing but the word test at the end of it it returns blog posts and we're going to get our repository out of the container first of all so we use this container which is given to us by the class we're extending we're going to try and get our classical repository we're going to say get all and then we're going to assert the count so we want one thing back usually I do this over a couple of steps I'm squeezing things in because of slides and time so we're expecting one thing so just enough that's enough of a test to make it fail for us to do it so first of all we have specified that we're going to use this article repository class but we haven't made it yet so we're getting an error that is saying service not found so service not found exception is getting through because we're trying to call something that doesn't exist so if we make it this will be our repository directory and call it article repository again the smallest thing we can do the simplest thing we can do to get our test to pass is just to make in this case an empty control an empty repository and because we're making it a service we need to add it to our services file for our module so I like to do services in this way I just use the full test name and the namespace and everything for it and then it's just as quickly tilled at the end again it's not something on the slides on the screen so again our error has changed it said we didn't have an article repository now we do so the next error is that we don't have a get all method so it's add a get all method so again we're going to want to have it return back an array so let's just return back an empty array now at a point we're actually getting a logic failure we're not getting a set of failure where the class you call doesn't exist we're now failing like our solution is failing now like you said we want one thing back and we're getting zero back so I'm going to inject the entity type manager interface into our class and we can use nice PHP 8 parotid constructors we get the node storage and in our get all we can now just say return this storage load multiple again like this isn't going to work as we get to the other use cases so we got other node types for example then it's going to return them all but for this test it's going to get work so again what's the simplest small thing that we can do to get our test to pass because we're injecting something to our constructor now we're going to just enable auto-wiring which is another tool on its own otherwise you could specify arguments and pass so each argument separately so this will just inject what we're asking for into our class so again we get this message node entity type doesn't exist because we're even trying to create nodes so we'll enable it in our modules array again the same as we did before and we're back to the situation again where zero matches one so in our test we also have a thing called a node creation trait so it's a trait but there's lots of methods on for creating nodes as the names have been applied and in there we can say this create node and we can specify the array of things because again like this if you're putting this on dribble.org it's not going to know about the content on your site because it's going to be a separate standalone module so you need to create this content within your test for it to work and make its versions against so before we do anything we're going to create a node so this is our arrange step at the top and the first third of our test then our act is we're going to get a repository and get all the things and then we're going to say do I assertion at the end so now we've got an article we've created an article our test passes so this is a constant red green refactor this fail little pass refactor phase that we're doing again now we're green we can keep building so we can either in this case something so we don't we get one thing back but is it the right thing so we can make sure it's an object first of all rather than a string or something else completely the index key one because we're getting them back from the entity type manager so they are actually it's not a typo honest it is actually the one that comes back it's node one that we've created so we're saying it's an object so the first one we return back is an object but then we can say it's got to be a node and then we can say it's got to have the correct node type it's got to be an article we've set our title now upon line two so we can then assert that the title is the correct title as well so not only now are we getting things back from our repository we can also make sure it's the right thing that we're getting back so how do we make sure things are published so everything we've done so far is we could have done really with the functional test we can make sure the text is on a page so because the test is at integration level how do you make sure that only the published things are returned that's pure art criteria we don't want to see our unpublished things yet so we can also set the status in this case we can just use the note that the constant for published are not published, it's on the node so this is just zero or one isn't what sets the status and we're going to say now based on this test and based on our arranged depths out of five nodes we're already expecting to see three so we're assuming our count is going to be three this is going to fail because we haven't written the code for this yet we're still returning back everything so we're saying we expect to get three where we're getting five so now we can go back we can go back into our node repository again and we can update our get all method so instead of saying load multiple, load everything we can pass now we'll switch to using load by properties and then we can use set status there and just add a condition to our query so now we only get back the published ones so again this passes this is a real one for a functional test we could say we see this text on the screen what we can't really do very easily is say this is first and then that is next and this is that we could look at xpath this is going to be much easier to test it so this time we can set the created date and let's set them all to have different created dates we're going to get now by default which isn't what we want so let's set them in an order we know is going to fail because we want to see this test fail first it's a little bit of an anti pattern to be like yes our test failed past first time you really see it fail first you know it's testing the right thing because if I put them in the right order they would just pass and it would work but it doesn't actually work the way we expect at all so the order I've put these in it needs to be 3 the 1, the 2, the 5, the 4 this is going to fail so we expect them to be in that order if we're sorting them in the way that we've said that we wanted the way our criteria says we should so as we expect I guess our test is going to fail certain the two arrays are equal so we'll just go back a bit so on line 15 here we're saying the certain same so we're getting the node IDs that we return back and then saying we expect them to be in this exact order we're not saying look at our page and so we want this h1 and then this and then that order we're literally looking at the IDs and we're getting back from our code so it's returning them back to it's not returning them back as 3, 1, 2, 5, 4 it's returning them back as 1, 2, 3, 4, 5 in the right order so it's just failing because we're not matching our expected order so let's go back in and we can make an update so we can still get our articles from our repository that we can sort them so we can use the UA sort function or PHP might be a better way of doing this and then we can pass to the callable and we can say node A and node B and then this created time is greater than this created time since the last time I did this talk you should be able to return back whether it was bigger or not as a boolean but now I've got to pass through as an integer so we get to use the call spaceship operator to say whether it's less than or equal to a greater which I thought was really cool so once it's sorted we return them back our test classes so there's a whole lot of delay to this as well so if I drop down and do some unit testing I've got the longer version of this if I do a presenter and that's like a unit test we'll do the simplified version of this talk so this was a tweet I did this talk at a user group in the UK a while ago when was this 2018 goodness me a screenshot that somebody had taken after this and said I've got this root test awesome 20 there's a lot of old tweets in this slide I've just realised so I tweeted that afterwards and the response back was this terrible quality photo for the total driver to test and it was great so far it's really helped me to give me a piece of mind to help me to uncover a bug I wouldn't have otherwise the main thing is about this confidence it's like again are things working the way you expect and tests aren't going to tell you where the things work but they're going to tell you where the things don't work so there might be use cases you haven't tested yet that you haven't found or that you still need to write a test for but if you've written a test for something and then later on you're changing it or you're refactoring something and you break it, you'll know because your test is now going to fail and I think that's quite common why people don't like extending or changing code or don't refactor code because it's scared of breaking it so if we can leverage these tests as a safety net and we can know that the test passed to begin with I've made all my changes and it still passes then things still work we did a big refactor on not big but a fairly large refactor options module a while ago and it was, yeah, we were able to do that because we had these tests in place so I started actually I started doing a code during the day when I started learning and then I wrote tests in the evening for that code that I wrote and I found a bug that I wouldn't have found otherwise and that's what really got me hooked on testing so thank you very much there's some links here to the PHP UNID documentation things and the Drupal org documentation my site is alloverdaves.uk and then the last thing here I'm going to be doing a free 7-day email that ultimately testing course for email so you can go to slash ATDC, Ultimately Testing Drupal Course put your email address in there and I'm going to finish that this week he says on camera we'll get there so yeah and this will just go a bit more into this detail from what we've just seen and we'll look at the UNID testing we'll do the full breakdown of everything in that course and that's inside the path for free so thank you very much


I'm going to watch it over and over again. Yeah, so let's record it then. So this one says, a penicillin derivative is used to treat infections with an adult 24-hour dosage of 35 milligrams per kilogram of body mass. This is to be given in three injections daily. So this antibiotic is prepared by the pharmacy in solution form with a concentration of 130 milligrams per 5.0 milligrams. What volume in milliliter should be given in each injection to an adult with a mass of 12.5 kilograms? So the first thing you want to do is get rid of some of these conversion factors. All of these are unit conversions. They've been turned to conversion factors for you. The first thing I really like to do is make these into something that's a little more manageable for me. Because remember how we like to put this, then multiply it by this, then this, and this. So we're going to do it in stepwise fashion like that. So well, we've got all this information. So we want to get the number of milliliters eventually. So let's go ahead and write these differently. So this one says the dosage is 35 milligrams per one kilogram of body weight. So this is kilograms of body weight there. So if we use those, we can already get milligrams from that. And then here, this is just a ratio written kind of weird, like text message way, all in one line. So how are we going to write it at 0.0 milliliters like that? So hopefully that helps you already. And remember, with these ratios, we can flip them this way or this way. They mean the same thing. So let's go about figuring out how many milliliters in all three injections. So remember, there's three injections for a 24-hour period. So let's do all three injections. So let's not worry about this number yet. So the volume in a 24-hour period is going to be, well, we want volume units. So the only volume units that we have in here is 5.0 milliliters. Does that make sense? So that has to be on the top. If that's on the top, then we're going to have to flip this thing over. So it's going to be 5.0 mills divided by 130 milligrams of the drug. Does that make sense? So we've done so far? OK, wonderful. So now we're going to multiply that by something else. Well, we want to cancel out milligrams, right? Is there anything up here that has milligrams in it? The top one up there, right? And we want the milligrams to be up here. So we're just going to write it how it is here. One milligram, or, sorry, 35 milligrams per one kilogram of body weight, OK? So 35 milligrams. And this is of the drug for one kilogram of body weight. And I put that body weight there, so milligrams and kilograms wouldn't be confused, OK? So now look what I can do. Milligrams cancels out with milligrams, OK? So now I have milligrams milliliters per kilogram of body weight. But I know how much the guy weighs, the adult weighs, right? 12.5. So I can multiply that by 12.5 kilograms like that, body weight, and that cancels like that, right? So what does that mean? So the volume in a 24-hour period is going to be whatever this expression comes out to. And I didn't bring my calculator. And do you mind if I use your calculator? That's terrible. OK. So the way I do it is 5 times 35, and then times 12.5, and then divide that by 1.30, yes, OK? And so to two significant figures, unfortunately, well, we'll just go out for right now, and then we'll do the two significant figures in a little bit, OK? Not that it won't matter, but we'll just say 16.8 milliliters. So that's milliliters per one injection, remember, OK? So that's, or per 24, per three injections, OK? Per three injections. Because that's for every 24-hour period, per three injections, OK? So this is 16 mills per, if you want to say, 24-hour period. And then multiply by this ratio here, right? So we got 24-hour period divided by three injections. So this will give us the volume per injection. Does that make sense? Because we're going to cancel out like that, OK? Does that make sense? Because it's like magic, right? It's awesome, huh? OK, so now we don't have to worry about 24. So we're just going to take that and divide it by three. And so each one of the injections to two significant figures, so it's better that we do it this way, is going to be 5.6 milliliters. And I think that's the right answer, right? Yes. OK, wonderful. So that was a good question. Are there any questions on this one?