 All right. Good morning, everyone. Thank you for coming back to Red Hat Developer Corner. And joining us today, Jeremy and I is Max and George. Maybe, Max, if you want to introduce yourself. Sure. Max Anderson just back from vacation learning how to use a computer again. My name is Andy and I'm co-leading Quarkus at the last couple of years. And yeah, that's me. George is O2. Yeah, so my name is George Eros or George Andrew Dacus. I work as a Suffer engineer on the Quarkus team. I've been doing that, I don't know. Probably lost track. What is it? Three or four years now? So yeah, that takes up all my time these days. Great. Well, you'll notice I have this big R on my chest because nobody on the Quarkus team has sent me a T-shirt. They sent to everyone who made a commit? Yeah, they sent a commit. Oh, okay. Okay, I get it. Hey, you guys, we can plug you. So these guys are frequently on Quarkus Insights, right? Actually, Max, you're always on Quarkus Insights, right? Oh, sometimes. Most of them. Most of them, okay. So for those who joined that think we're going to talk about open telemetry and micro-profile, we kind of had a little glitch. We're actually going to talk about unit testing today, so I hope you stick with us. And we're going to talk about the Quarkus unit testing that Jeremy's been teaching me. So we'll see how that goes. It's not in Rust, right? So why don't we jump right in? I'm going to share my screen and see what happens, right? So tell me if you can see my screen. Yes, you good? All right, so for those who are interested, Jeremy and I stuck our code up here. So this GitHub developer corner stuff, and we have a bunch of basic Quarkus unit testing stuff there. So what we're going to do today, though, is we're going to walk through a little project and look at how we can add some unit testing to that. So all we did here was we went and generated a Quarkus project to get us started. And the only thing that it's got in it so far is we added, you know, REST easy basically with Jackson, and then we added some hibernate panache to it. We created a simple database that we're going to use. We're going to do a very simple book example here, and we added some properties to get that going. But you'll notice we have a model, one entity in there, just a simple book, a repository pattern, and a service, but we don't have any resources yet to access it. So what Jeremy... Is it just me or is this screen very small? Oh, is it? Okay. Sorry. Let's figure out how to get this. Is that better? Yeah, bigger phones are better, but yeah. Is it? Okay. All right. Let me know if you can't see something so that I can... Yeah, maximize that piece. Yes? Yeah, maximize that piece. It'll be easy. This part here? Is that better? Okay. So all we're going to do here... Sorry, I'm going back here. We're going to add a resource. So Jeremy, stop me when I mess something up. So what we want to add is a book resource so that we can add, get to this code, right? Why did it do that? It never works on the... So let's add a path to this. That's it. That's all we got so far. So let's inject our service because we want to get to the service. So Jeremy likes using services. He tells me so that he can add validation to it. Is that right, Jeremy? Yeah, it's easier to test it. Okay. And what do we want to test first? Just to get all the books that we stuck in the database for the initial project? You know, I can type about 80 words a minute if I include the backspace. So what do you think? That'll work. I haven't added any testing yet. So the way I normally test is I'm going to build it and run it. And I don't do this unit testing and Rust kind of thing. So... No testing needed in Rust? No, because the compiler yells at you about every little thing. So it really makes for good code but like triples your time to product. Well, you can test in production that way too, right? Yeah, exactly. And there's no exceptions, Max. So just think about that. Nice. All right. So we're doing this live coding. So Quarkus, maybe one of you guys want to explain what live coding is? Well, so we have, in Quarkus, we call it dev mode where when you run Quarkus in dev mode, Quarkus dev or maybe Quarkus dev or Gradle Quarkus dev or you run it from the IDE, it will just run your app and then it will look for changes. Whenever a request comes in, it will check, has changes happened and then if there has, have been changes, it will compile and you get the update and restart. And it's different than like normal like reload where we only do it when it's necessary where others tend to rebuild every time there's a change. So it lets you like play around and do changes and it's only when a request comes in, you actually don't have to deal with compiler errors before you're ready for the change to happen. So yeah, that's the dev mode of, yeah, what we call live editing or accounting. Yeah, it's also awesome. It is pretty awesome because I, normally I'm wearing a C++ t-shirt and we don't do things like that there. Well, you have all the time in the world, right? Yeah, exactly. You have more time doing development. So I went ahead and pre-created a couple of tests the way I would test it in Postman. So I'm just going to send that out and sure enough, we get our four books and those four books were imported here into the database. The database is not actually, it's actually running in the dev environment now, right? Yeah, you probably, yes. Yeah. That's another feature we have in Quargers Dev Mode that you can add like, I'm not sure what you have here is Postgres or H2 or something. But if you just have a dependency. Oh, yeah. So here you see that only the prod mode is configured but in dev mode or test, there's nothing. So what Quargers says, hey, you have an added entity and you have a data source. We will create one for you in a dev service. So if you run H2, it will be starting at H2 in processed Java mode. But if you are doing like Postgres or Oracle or MySQL will actually start up a Docker container or a container using test containers. And again, this is one of the things that just magically works and you're surprised when you see it the first time because like, you normally have to, oh, we have to have a separate dev instance and configured and booted up before you run. But all that's happened, it's all managed by Quargers. Yeah. So that's the dev service. Yeah. You have Docker desktop running. Pop up your Docker desktop for a second. Everybody can go to see it. So if you haven't used Quargers dev mode before, you can see test containers as spun up and a database, which is really nice. I don't even use H2 anymore. I used to use H2 for everything. Yeah. But you can just use Postgres, right? Yeah. Yeah, there's no reason to use H2 anymore. Yeah. Well, that's good because the last time I used it was with some EAPs. Was it EAPs? A couple years ago. Yeah. So I almost never use it. Everyone uses Postgres, I think, pretty much. Oh, I was using H2. I used H2 forever for a long, long time. Oh, really? Yeah. But it was, I mean, dev mode just kind of kills it. So what? Need for it, right? For any production stuff where you're using it, like in production, you're using a real database, there's no need to. H2 has a lot of uses, like you can write in a CLI or some small thing. But for testing, you might as well just use a real thing because it's so easy now with test containers and dev services. Yeah. So Jeremy likes to test everything first. I'm going to keep blaming him because he drags me into this stuff. Yeah. So what we're going to do is, let's create a test harness for this. So what we're going to do here is add a Quarkis test. Right? And we're going to, do I need to add the test to HTTP endpoint? Yeah. I think so, right? You don't have to, but you can yet. OK. Just for completeness. And the cool thing, Quarkis test in the background is going to spin up another instance of Quarkis running on a different set of ports. Right? So you don't have to pull your running server. And these tests are going to run in the background while you're coding. It's a really, really nice feedback. Yeah. So, and then this is, yeah, it just works. And, you know, one of the things that's nice is like Quarkis is very much focused on performance and using a little resource as possible. And that is for production and the test runs. In Dev mode, we are assuming you have a laptop or machine that has a bit more room. And there you run basically an instance for you to play around with, like a play area. And then a separate one for the test. So you can, you know, you don't step on, step on each other's toes. So while we're talking, I'm starting to write this test. And I know this part. Right? Rest assured and content type and content type JSON. So what is this bit here that I'm going to start adding? Yes. Also, if you're following along and you haven't used rest assured before, it's bundled with, or it comes with Quarkis out of the gate. If you're using any of the rest easy stuff, which is any of the web stuff, it's going to pull in this library rest assured, which is a really great library that makes it super easy to test any kind of any kind of web things you're doing, you know, all your crud stuff. And you got a static import. So you can just use given. And it's a really nice API for creating tests. And hand-pressed matches are pulled in too. So the matches are really nice. So anybody read the three-body problem yet? The science fiction book? Not that I recall. So I wanted to read these books by Zix and Lou. I think that's how you pronounce that. It's called The Three-Body Problem. Before Netflix made a series out of it and ruined it. So it's really pretty good. It's a pretty good science fiction series. So anyway, so what I have here now, and I'm going to go ahead and talk about it. So anyway, so what I have here now is what I'm hoping is the exact same thing that I'm doing here in Postman. So I run this and I get my titles. And I want to get all the books back. And I'm just testing that it has these authors in it. That looks good, Jeremy. You just need a semicolon. That's true. Oh, you guys in your semicons. Okay. So in C++, the curly brace goes here. How many times have we had arguments over that? So let's run this test and see what happens. This is the part where I get a lot of red or something on the screen. No, it ran. Wow, that's great. Look how easy that was. Yeah, no errors, no exceptions. That's right. So let's add some other stuff here and for time's sake. Maybe you want to go and add an error to the test just to check that you actually are running the right thing. Oh, I'm really good at adding errors to things. So let's never trust a test unless you've seen it fail. Never trust a test unless you've seen it fail. All right. What if I put a misspelling in here? Hey, there you go. And what kind of cool error message did we get out here? So we said, we got a collection back containing the right names. But, you know, our comparison here didn't have this section in it, right? Yeah. Yeah, I didn't tell you that the key was different, but that you didn't get. I mean, no, no, no. The error message makes sense from a rest assured perspective because it's looking for a key. Yes. Yes. Can you see that? Or is it too small? It's too small. Okay. It's too small. All right. We'll run it again just to make sure that it worked. All right. All right. Cool. All right. All right. Cool. Perfect. All right. Let's add another method here. So let's do the rest of the crowd operations, right? So let's do a post. I love IntelliJ or basically all the JetBrains tools. You guys use VS Code. What do you guys use normally? Whatever works that week. But yeah. Okay. VS Code IntelliJ. Did you see that big giant bug in VS Code yesterday? No. About it's stealing passwords? No. Oh, yeah. Yeah. What's that all about? I didn't hear it either. There's some kind of, you'd have to look it up, but there's some kind of issue where you can steal passwords from your VS Code environment. So when you're logging into things with VS Code, you could potentially be giving your passwords to somebody. That's on all VS Code environment. I don't know if that works on Mac, Windows, or everything else, or it's just on Windows. I just looked it up. Extensions can be malicious. Don't trust anything you download from Instance. Anything has a plug-in. So apparently the way that the application works, the extension can list in on your type again, the password to another extension. So yeah. So I'm going to add a put here also. So we want to create something, and now we want to update it. All right. So let's use this good old-fashioned try catch, because Rob writes a lot of stuff with errors in it, and the compiler is not going to stop me here. Invalid parameter for exception. Yeah. Sorry, you guys have to watch this. I know you're in this all day, but... Oh, it looks good. Okay. So we just added this code. I'm still running. So we should be able to go over to Postman and actually run this, right? So we should be able to do a create. So I'm going to create one. And sure enough, I added it. And we want to update that from... Well, we got back to five, right? So we're going to modify that. We're going to say change more of the worlds to invisible man, because we did the book ID, the book. So let's test this. Let's actually write a test for it. What do you think? See what's happening here. Sounds like a good thing. That sounds like a good thing, right? Writing extra tests for debugging is an underrated way of debugging things instead of using... All right. So what I really want to do is create and an update, right? All right. So we're going to create function. Next, what do you think? All right. Guys help me out here where I'm messing up something. What are you trying to say without a transaction? Yeah, I'm going to do this create here. Let's create a different one. So William Gibson is another author that I like. So let's do that. Anybody ever heard of this book by William Gibson? Neuromancer? Yeah, right there. Yeah, I started with genre, right? So that whole genre with, you know, what do they call it? Some kind of techno punk thing, right? I said that's cyberpunk. There you go. No, I'm not a fiction fan myself. Oh, what do you usually read? Nonfiction. I like what? Ah, history, politics, stuff like that. Ah, okay. So right next to me on my desk here, I have a nonfiction book. I don't know if you can see it on the screen. That won't put you to sleep at night. I can't make out the title. Oh, you can't? It's a history of the Sasanian Empire. Oh, okay. Excellent. For me, it looks like a good night. It was a lullaby story. Is that, to get your kid, you don't try good night moon. You go straight to the history of the Sasanian Empire. Yeah. But you know, I just remember it was like a Miga game. Was it really? I just remember the romance. I didn't, I didn't read the book. First I learned it from a game. I believe it's like a Miga or something. It was like a long time ago. I think probably the last like fiction I read was probably like some Scandinavian murder stories, stuff like that. Really popular around here. Yeah. I have to alternate between fiction and nonfiction. But the nonfictionary doesn't necessarily make me look smart. Doesn't necessarily. Sorry. Didn't get you. Doesn't necessarily make me look smart. Like football packets. So let's see if we, you know what? I'm thinking that I'm going to have to write a test here for, to test. So we actually have a test that we did to create. But what about testing it with a, what would it help if I put a new in there? So let's actually test that. So this should work by creating a title with an author. So we're, that's different. So we're going to do Neuromanswer by William Gibson. And then we're going to look that up by title. I just looked it up. It was 988. I'm feeling old now. Was it really? 88? Yeah. Is that like it? The game came out in 988. Oh, the game came out 988. Okay. Yeah, the game came out from 84. All right. What are your recommendations on how to make the test fail first? Since we want it to fail, right? It just assert a wrong, you know, it assert something you should be wrong. Yeah, it's code. Yeah. How's that? Yeah, sure. Yeah, just something to make it fail. See, now you've got a problem, right? Yeah. That test doesn't fail. It's all good. Yeah. Yeah. Now why? Test in production. Ship it. Ship it. Now is this, is this going to run different? Is this going to run different if I, if I rebuild it? So I stopped the live code and rebuilt it? No, it shouldn't make a difference. It should be the same. It should be the same. So why do we think that that's going to work there? Any ideas? Jeremy? Anything? No, I just run it. Well, you don't, you don't, so you do, you do assert. Yeah. Yeah, right. So I did an assert here. We got a 201 back. Neuromancer. We did a query. Yes. We shouldn't get the title back though. That should be. Okay. I see what the, you're, you're not performing a get anywhere. Giving content type, pram, then. Yeah. You need to say get. Yeah. Yeah. There's no when get then. There's straight then. Yeah. The rest assured DSL doesn't save you from that. That's happened to me a few times. So you win dot get. And that should be another thing. The, the only thing that I, the, maybe I did, I mean, I love rest assured. I think it's a really great library. The JSON path I found it took me a while to get used to their JSON implementation when you're really complicated stuff. Yeah. That's no fun. Yeah. I don't have a really good workaround for that yet. But. Man, neither do I. Now we failed. Actual zero. Cause we don't have anything in the gap. Right. So what we really want is the ID, right? That just got generated. Yeah. I think the used. Yeah. Use the, the ideas, the path. Yeah. But we, but we, we really wanted was this query. Right. So do we not have a, we have the ID, but we didn't actually, we have a query param here. So what do you guys think put down the spot? Well, what does book service. Yeah. Find actually do. So book service dot fine. We can pass it a query and do the repository find all. And we're going to do a like, whatever the query is. I don't see how is, how does the query represent like name. Or whatever title is. Okay. Sorry. The title is on. It's already in there. Okay. Got it. Gotcha. So what we need is the resource that we need to fix this. Right. No, I think that one. I mean, if the database is populated properly, that's, that should work. Do we need to fix this? Okay. So how about, Okay. Yeah. Neuromancer, blah, blah, blah. Okay. But hold on. So you're running. Okay. You have to get on. Okay. I see what's going on. You basically the way the test is written now, you have no guarantee that your get this, this get book with query prime is running before create. And actually, if you look at what IntelliJ is doing, it's running that one before the create. So what do you need to do this? Can we add order? Yes, you can, but you need to add an annotation to, to the test itself where you say, I think it's the annotations called like method order or something like that. Yeah. Method. Yeah. I got it. How about this? Test method order. There you go. Yeah. And then you need the, in here, blah, blah. That's not it. So like, I don't remember what the name is like, you know, order annotation or something like that. Yeah. So we actually need to add, five test method order. Yeah. Okay. So it's called method order dot. Order annotation. That class. Yeah. And then we can add this as a second order. Yeah. You know, so you added one to create in two, two. Yeah. Okay. So that should probably work. Well, I'm glad we got the experts on here, Jeremy. We're going to watch this later. We're going to watch this, fixing this for a long time, right? Yeah. Well, I mean, I've looked at so many user provided applications where they're like, this isn't working. Some, it's Quarkus problem. Yeah. So, I've learned to spot things like this. It's not a Quarkus problem. It's a user error problem. Well, it sometimes is. I mean, so let's, let's, let's add the delete. And because I'm, I'm kind of running out of time. I'll, copy the lead in here. How's that? So, because you guys don't want to watch me write that. So what we're going to do is we're going to say, deleted by ID. So what we did was, we did a test get, we did a test post to create something. We did an update to it. And we did a delete, right? So if we run this, we should be able to test all those things in postman. All right. So we did all that stuff in postman, but we don't like postman anymore. So we're going to do is we're going to add this. Delete to our test. Right. That makes sense. Okay. So, and because we just tested this with a particular order. Test normally need to run out of order, but if we're going to do something. This, we're going to add some order to it. And we're going to say void, remove, because we don't want to just call it delete. Given content type application. We'll do that. And then we'll say, when. Delete. You know, too fast on the tab, right? And we think it's probably number five, because we didn't, because we only had four when we inserted into the database. Then that is code. And what's the status code on a delete. To go for, right? So now we should be able to create it. Make sure that it's actually there. And delete it all in order. Voila. It looks good. All right. So, but what if I want to test this in a. In the container. Is that an integration test? That should be pretty easy in. Right. Sorry, you want to do what? Kind of an integration test. Okay. Yeah. So. Yes. We're an IT on the end. Do we get. Because integration test. Yeah. Like that. Should be that easy. Now can I run that in live mode? No. Okay. So I have to stop this. You need to package the application for this. But if you, you can try and run it. I mean, if you try and run it now. I think the error message. Should be fairly clear. Say that. You haven't. Package the application. And therefore you can't actually execute this type of test. Against it. And it might be worth mentioning a different right. Like. The, the, the, the rest of short testing is actually testing the end point. Which is, you consider it like a black box testing, but it is still running in like dev mode and. We do a lots of, a bunch of shortcuts. So things are easy. When you run the. Integration tests. The intent is to run like. A fully package application on its own standalone and tested from fully outside. Not that you can do with a package jar. In a container or also a native binary. Right. Because a native binary cut. Tests in, in this dev mode. Also not a jar. So that's, that's the reason why we have this separation. So I got out of the dev mode. I did a build. I'm going to run it here just to see what's going to happen. And I'm going to put. So it's going to create a bunch of stuff here in Docker. What's going on there. So it's the same. Okay. So I think what. This is going to go away. Right. Okay. Let's see what's going on here. Yeah, well it starts test container. I mean, it does the same. Just right. So what I would really need to do is package this up. And then. Then run this test. Right. How about, how about try, try like a maven clean first and then run this. And that, that should fail. Because if you've, if you've been, if you built it prior, this would, this would work. Okay. So now I'll just try like, yeah, running this. Yeah. Yeah. Okay. Yeah. And the error message should tell you that you haven't packaged the application. I mean, yeah. If you go down, let's see what it's saying. If I can't make it out. Oh, I'm sorry. Yeah. Make sure the test is run after the course application has been built. Yeah. Okay. That's right. Yeah. As Max said, basically the idea is that if you're going to run the application. Yeah. As Max said, basically the idea is that this is a process of testing a running application outside of the application process itself. Right. So this is just like, it's like running postman against a running against the Quark's application. Only in this case, the test itself also starts the application, whether that's a container or Java, Java jar or a native binary. It doesn't matter. So what if I, if I want to add something to look at the test coverage, we can simply add Jacoco to this. Right. Yeah. That should work for the Quarkus test. Yeah. Well, yeah. You have to, with one addition to your palm, it'll also work for anything else. Right. Yeah. The first time I did that because I have a mix of Quarkus tests, right? So stuff in isolation. I remember like being very disappointed for a while that I was getting zero coverage on things that I knew I had test coverage for it. But isn't it? But, you know, being a developer. They're Jeremy. It's code coverage. Just code coverage. So I, all I did was add this to the palm. And did you see how I accidentally started trouble the other day on the, on the app. I put an article in there about why Gradle sucks. No comment. People like. I know. I'm a, I, it didn't, it wasn't actually an article about why Gradle sucks. It was just a comparison between Maven and Gradle. And it started this whole religious. I really like Gradle as long as it's important. Say what? I say I really like Gradle as long as I don't have to support it. So what we were. What we ran here was all I did was I added you go go to the palm. And after I ran the test, I got this at the bottom here. So I'm going to cut and paste that into my browser and see what I get. Oh, well, I got a whole directory there. Right. So we'll always go to the index HTML. So what am I seeing here? This is. This is. This is. This is. So what am I seeing here? This is. All the stuff that just got run. So the model got hit. It's a lot of red. A lot of red, right? Because I didn't actually run a test for everything. Right. So we did the resource, but we only hit a portion of the resources. Right. To get to create the remove. Okay. But I can see my test coverage. And the only thing I had to do is add something to the file. That's pretty slick. I like that. Maybe you want to show it a continuous testing to. Talking to her. Yes. If you run a quarter step mode. Yep. Hold on. Yeah. So. We could do this from the terminal, right? So. Yes. We can name in cork is dev. Right. So we could do. Maybe. Cork is dev. But if I'm a pointy clicky kind of person, I can do it over here and just. Find it. Run it. Right. Yeah. And then you start up. It was just say something like you see in the lower part, it says. Test post. So normally cork is a startup being like, no, like normal. You can do you can run the, let's call the play mode. A demo. But if you go scroll down to test. The pause is like resume testing. So if you click are. A pressure. I did. It starts running the test in the background. All my tests just got run. Yeah. You know, it's green. Now you can go into the test before and just like change the, the get. Whatever the test where we're feeling. How do I see which one's failing? Yeah. Well, they all green. So just fix. Green. Yes. Change something like. So. Right. Six right. Because we didn't do that. Yeah. Okay. And then it should be picking up in the low. Yeah. Yeah. Broke it. Now fix it. It'll actually. It'll run super fast too. Yeah. So what it does is so that the, this actually the fun story here is like when we dipped corkers first. Oh, sorry. The first version of corkers. We had death mode. We didn't have a continuous testing. And then 50% of the crowd. You know, users say, Hey, this is awesome. We can do all the experimentation. And then the other part said, Hey, I can't do testing. That's why I have to do testing first. So we came up with this proposal that we want to do continuous testing. So when you, you can do, you can be doing all this for fun playing around. But you also get feedback immediately. If you break your tests. So it kind of allows you to have fun while also doing test driven development. And what it does is even if you had a lot of tests, it keeps track of what code paths are being affected. So if you have a hundred tests, it will should only run the ones that are that failed or the ones that are affected. Like it tries to be smart on what running. So it doesn't run the full test suite all the time. It can also tweak and configure it to be a subset or whatever, but it's trying to be smart. So it's pretty nice. Of course, if you're used to not having tests, then this is not interesting, but this might want you to have tests because now it's not a big problem. So I want to add, I'm going to add one more thing and then turn it over to Jeremy because I, I like to add, you know, I come from a world where everything's a printf in order to debug something, which is horrifying, right? But I learned this cool thing that you guys added here where we could get callbacks. And while I'm adding this, maybe you want to talk about what callbacks are, Jeremy or somebody. What are you adding a callback for? I'm just going to add a callback that says what test methods I'm executing because I couldn't actually see all that down in the terminal there. Yeah, so this is usually used for like integration with other stuff. But yeah, nothing prevents you from like adding it to the application itself. But yeah, so this is similar to G units before each annotation. But I think this provides you a little more information. A little more contextual information that is. All right, so because I like to print stuff out, we're going to do this. I remember the days when we didn't even have unit, we just did assertions inside your code. Sounds like fun. That was, you know, 25 years ago, but it was just chill my age here. You guys really, this is really great. I mean, if you come from most people nowadays, you know, they're, they're looking at stuff and going, oh, this is just, you know, the way it should be, right? You know what you guys have added. But those of us that have been around a long time and had to do things, you know, the hard way, you know, walking uphill in the snow both ways, kind of thing. Did I put them right? Makes you think what we'll, what we'll be saying in the next 20 years. Yeah, kind of, you know, what, what, I mean, this is, this is really good stuff. I mean, I don't envisage yet, you know, any, you know, me telling the computer, hey, you know, right. That may be coming, who knows, right? Yeah. Finally, a double, a double colon. That's my world. That's what C++ uses for, what, virtual calls or something like that. Yeah, everything. All right. Now we got to add something in here, though, in this meta-imp package, right? Yes. Yeah, it's not picked up automatically. Yeah, so that's, yeah, it's a little manual. Service, right? Yeah, meta-imp, yeah, under meta-imp service. Oh, you know what, went under dot resource. Yeah, that's what Retellogy does that automatically. Yeah, so you have to move that. I have to move that, right? Yeah. Move directory. God, refactoring is so nice. So I need a file name here. The file name is the name of the class you're implementing, basically. Yeah, I don't like it. The cork is test before callback. Yeah, so I need a file name. So let's add a file. io.corkus.test.junit.callback.corkus-test before each callback, callback. Now I can put the name of the thing in there, right? Yeah, your implementation. Acme dot this thing. Yeah, exactly. That should be good with that, right? IntelliJ seems to not like it. I don't know why. Is it telling you why? No service provider. It doesn't make sense there. Let's refresh that. Let's just run the test and see what happens. Yeah. It might be just some IntelliJ thing. I think I saw it. So we said executing and then the test. And then I printed off the annotations that were on that test. Nice. Very nice. I like that. Now I can see what's going on from us. So we can enrich this in a number of different ways, right? There's a bunch of different callback types. I like that. That's cool. Especially if I'm integrating, I've written stuff where I've had to integrate with downstream services that you paid for every time. And even when you hit it in test. So Jeremy's going to talk about how we're going to mock some of that out. And I know we're right at the top of the hour. I apologize if you guys have to jump or something, but it would be great if you could stick around maybe a little bit longer for Jeremy. You want to take over? Sure. I'll go really fast. Yeah. This is what happens when you stick somebody who's not a native Java developer in Quarkus. But what I'd like to say is look how easy that was. Can you guys see my window? You can now, yeah. Yep. All right, now you've got to make it bigger. Why is that? I'm happy you liked it. I'm looking forward to your first contributions. You can have a new shirt next year. Oh, I'm going to get a Quarkus shirt somewhere. All right, so the first thing I want to show, I'm actually going to start with Wiremock because somebody asked to start with Wiremock. So I've got an app. I've got Quarkus running in Dev mode right here. And I have since this weekend, the Premier League starts, I thought we would call an API and I'm calling into an API to get Premier League fixtures, fixtures. And so Saturday, we can see we've got the results are getting back. I'm making an API call. This is to API-football. And we've got, it's in Turfmore, right? So it's Burnley and Manchester City. So let's come over here. Let's look at what this application is doing. We looked a little bit at this before. So how's that? See that pretty well? This is pretty basic, right? Our path is right there, PL fixtures. I have a REST client API football service. And I'm really just returning that as a pass through, right? I'm passing in the parameters that the API wants. If you want to look at what the Quarkus REST client looks like. Here we go. I've got a couple of things going on here. They require this configuration key. I've wired up where this URL is inside my application properties. This is a custom header that has my key. I've added that on the command line so that I don't accidentally commit that into source control, which I do kind of regularly and then regenerate my key anyway. And then I have get fixtures by date. This is just an interface, right? So Quarkus is going to implement this for you. I've got all these query prams. This all looks pretty normal if you're used to using any of the REST easy stuff. So the way we test this stuff, I want to use WireMock. And what WireMock allows me to do is to spin up a Java server that's going to mock out my response and lets me control that response. So I don't have to ping against this API and pay for API calls while I'm doing my testing and development. So this is a Quarkus test resource lifecycle manager. So I guess it introduced two things. What a Quarkus test resource lifecycle manager does is this allows us to annotate one of our classes with this. Where's my class? If you have both, we're really standing test. So I can annotate the test with that. And it's going to start up another version of Quarkus, right? So we mentioned before that in the background, there's one version of Quarkus running, putting a test resource around it. The lifecycle is going to start up a second version. But it also means that it's going to make whatever happens there is going to be available here. So I've got this, my WireMock proxy. WireMock server, we haven't used this. It's a really great utility. It's got a website, pretty good docs. We start up the server here. I'm listening on port 8089. And then what I'm doing is I'm, what I'm doing here is I am stubbing this out. So I'm first, I'm going to intercept everything. And then I'm going to return a call proxy to, you know, the API service that I'm using, right? And then when I get a specific URL, I'm not going to return that. I'm going to return a canned response that I've got here. And this is my canned response. The way I'm going to know this is that we've changed Burn, we've changed Turfmoor to Main Road, right? So we're going to get the wrong answer back. But as long as that's what I'm expecting, then that will be correct. I mentioned that we've got Quarkus, Quarkus is running in the background here. Let's, and then we, the method, the life cycle has two methods, start and stop. So it cleans that up. So our test here, where's that really extending? API football service test. And this, I'm just testing. I'm just testing that my REST client works. So we can run this thing. Let's run this. I passed. So again, I'm expecting, I'm expecting the wrong thing. So let's put this in. We were talking about earlier. We always want to see, make sure our tests, you know, are accurate. So if I run it this way, I'm going to fail, because I'm not going to actually call the API. I'm not going to get back the real number. I'm not, I got back Main Road instead, right? And we noticed like, so Quarkus in the background, hit R for resume testing, right? And so in the background, we'll see our test will crap out and it fixes so fast. Jeremy, we lost your screen. Okay. Let's go back to that. Can you guys see it now? No. All right. Better. It's telling me that I'm sharing. All right. Let me, can you guys see it now or no? No. No. All right. Sharing. Share again. Screen one. Share. I got a little message that says I'm sharing. All right. There we go. So we changed that back and it's already passed the test. So that's how I test the REST client, right? I've mocked that out. I've intercepted this call. You can also just mock. And this is also we'll begin looking at mocks. So now I want to test my REST endpoint, right? The one that we're looking at that I'm looking at here. So in that case, I don't have to need to round trip that. I can just mock the API football service itself, right? So I can inject mock, tell it that it's a REST client. And then before my method, I am going to say when I call this method, then return. And I've got my own method for that, right? And so this is what I'm returning. So I'm just going to return this object again with the wrong. I'm going to turn it with the wrong venue, right? And I mentioned earlier the one kind of gripe I have around REST easy is that I think the JSON path is a little bit wonky, but you can get through it once you start looking at how it comes back. But it didn't work exactly the way. Maybe it's because I spent a lot of time working with Vertex, which I think has a really, really nice JSON implementation. So I found it really a little bit odd. What I'm going to do here is in this case, this is also another version for REST easy. I can also get the response out, and then I can just get the JSON out of the response, right? So I get responses string and get the JSON out and then parse through my JSON because the JSON I'm getting back looks just like this. So it's a little bit complicated here. Where's my utilities, test values? So this is the JSON I'm getting back, right? So it's a good bit of JSON, right? Nested stuff. I've got a raise in here. So some decent work has to pop through here. So let's run this thing. We can see the mock, and so we're working there. And again, this time I don't have to mock anything out. I just tell it to return whatever I tell it to, right? So there's two different ways you can do that. We can do WireMock when we actually want to proxy to something, or we can, when we want to test the REST client itself, we can use WireMock. Otherwise, we can just create a mock. So let's look at a couple other mocks here. Stop Quarkus there, hop over to this project. So in this case, I have got, let's Quarkus Dev, fire up Quarkus here. Let's take a look at this UI I've got. It's a local host. I've got a local group for Premier League Pictures. We're going to do hello, so I've got some hello. And now I'm returning some random hellos, right? So hello from a number of different languages, right? I've also got a local host, 8080, quote. So we get a quote, right? And we've got some random quotes, right? So we can pass back a few quotes. These are all coming back from the dude, but there are quotes from a few different authors. There's Walter, right? So we have a few different quotes. So for testing this, two different things we can look at testing here. The way that the rest endpoint looks, let's close this. The rest endpoint looks like this. At hello, I have two different services. I have a greeting service and a quote service. They're both fundamentally the same. I just have a list of greetings here in memory. You can see that. And I'm just returning a random one of those things. And then quotes are the same thing, right? So I've got this list of quotes here, and I'm just returning a random quote, right? So I return in hello, I return a random greeting, and then in quote, I just format the greeting, the quote object. So it comes back like that. So tests we're going to do here. The first thing I want to test is... Now, I've got, notice down here, my quote test, I'm going to call, I'm going to get one of these random quotes back. And this is another thing I mentioned, the Hamcrest matches. This is baked into Rest Easy. So I've got this Rest Easy given when I get quote, and I can say contains any of dude, mod, or Walter, who are the three authors of these potential quotes. So basically, no matter what quote I get, I'm going to get one of these authors, and I'm just making sure that one of these comes back correctly. Hello endpoint, I'm getting back random greeting, which is not part of my greeting service. I have a mock greeting service here. I have annotated it with mock, it's in my test directory. So Quarkus' automatic, or Quarkus' test, is going to automatically substitute my greeting service with this object everywhere in my test. It's good and bad, right? So one, every single test I run, it's going to use this instead. So I'm always going to get back this mock, this random greeting service, right? Whereas in this case, I'm going to get, I'm calling the actual object. So I can run that, and this will pass, right? Because I'm going to get back this random greeting, which is not one of the greetings in my actual resource. Another way we can mock things out is we can... So in this case, I'm going to create my, I'm going to inject my mock directly into the test. And what this means is I'm only going to have a mock of quotes service here inside of this test. So my other test was using the regular quotes service. I was getting back a random quote from one of those three actual people. Now, this one is going to use the annotated mock object, because that's for every single test case. And in this case, I'm going to need to train my quote service, right? So I'm going to say, when I call the method random quote, I'm going to send a new quote, and sometimes you eat the bear, and well, sometimes he eats you. And that's the stranger. It's not Maude or the dude or Walter. And so this case, I will get my quote back here. Right? So run that. And we'll get that quote. It's two different... So there's two different ways, right? If you annotate a beam with mock like this, it's going to be injected across every single test that you have, right? So you want to do that if you know globally, I don't want to use this thing, right? And then if you inject a mock inside of your actual class, you get more control, right? So sometimes I want to use a real thing, sometimes I don't. This is more obvious, I think, if we start looking at panache, right? So we'll be looking at some database stuff. Look at the way you mock out panache. So let's quickly, we will jump over to panache test. So in this, I have a... two of these things, but let's start this up. That's it. That started. So what Quarters Testing Panache does, I have two different greeting resources, which are two different ways we can use panache to store stuff in the database. The first one is an active record greeting, which is going to use the active record pattern. It means that I have a... In this case, I have a get where I'm saying hello, but I pass in a name. If the name is null, I just return hello. If I have a name on the format, then I create a greeting object, persisted in the database, and then return hello name. And then I have a list all, where I can call greeting list all. Panache makes it really, really easy to do this. So my entity, if you haven't seen panache before, extends panache entity. It gives me all these kind of methods that I just called, like list all here or persist. I can also do all kinds of querying and stuff. So let's take a look really quick here. Let's say hello. And we just have hello, but then I can say... So let's say hello and let's say all. Let's see if I've got... And I've stored that in the database, right? But when I want to go to test this, let's say I want to test my active record greeting test. So one thing we can do, and this is... A lot of times when we're testing, and traditionally I used to do a lot of this stuff. I mentioned I used to use H2, used to do a lot of this. I'm actually going to populate something in the database. We can do this in our setup method. It makes this really easy. Panache makes this really easy to do. And so in this case, when I call this endpoint, I'm going to get... If I call it empty, I'm going to get hello, right? That's expected functionality. And when I call hello all, I'm going to actually get one greeting because I've put one in the database, right? So I'm physically calling the database. This is really an integration test, right? But there's going to be one in the... There's going to be a greeting in the database. So when this test runs, I'm going to come back with Christopher, right? So Christopher Robin got put here in the database. Yep. Now, you don't really need to do that with Panache. And I think it's sort of... You're really doing an integration test. You don't want to test Panache's functionality. Red Hat wrote that and it's going to work. What you want to do is mock out your object, right? So now I have a different greeting resource test. And in this case, I'm going to mock out my greeting class. And I'm going to say, when we call list all, then return these three greetings. So then when I call this method, which is my front-end hello all method, body contains string. I'm only testing for one, but I can put contains... I can do multiple contained strings. And have a test for all three of these. The other thing, there's default values for all of these. So I'm not actually putting these in the database, right? I'm just mocking this object out. And it's going to say, I've got three of these things. But then if I call something like count, which is going to tell me how many are in the database, it's going to give me the default number of zero. And there isn't actually anything in the database. If I wanted to see what was actually in the database, I can mock the class. I can tell it to return three objects when it's called. And then I can tell it to call the real method, right? So don't mock out this method. Just mock out one of the methods I want to use. So this time, when I call hello all, I'm going to get one thing back because I'm putting one thing in the database, right? So I have one greeting in the database, which is Christopher. I've mocked this out. I'm not going to get Christopher. I'll get Poo, Tigger, and Eel are here. But I'll have one thing in the database. And I'm going really fast. So if this doesn't make sense, shout out, questions, yell. What's the difference between a spy and a mock? So a spy is just going to tell you that something got called multiple times, right? Or a number of times, right? So where's a spy? I have a mocker. This is a different spy. So what I'm going to do here on a spy is, for instance, I inject a spy instead of a mock. And what it's going to do is just say verify that greeting service was called one time, right? Because I know I'm expecting, I'm really testing my rest endpoint here. And I just want to know that the rest endpoint calls the appropriate class one time. I don't like hero comes back. So that's what we use a spy for. And then one last quick thing we'll show how to test Kafka because this is really useful and this is a really great piece of small rye reactive messaging. So inside of my Kafka test, I have a Hello Kafka resource. And this is a pretty simple resource. I'm listening here. This is reactive messaging. I'm listening to a Kafka topic called Hello in. And I'm publishing to a topic called Hello out. My method is called on Hello in. And what it's doing is it's taking the Hello message and translating it to an uppercase and returning it, right? Super, super simple. This can be a pain in the butt. I used to before the in-memory, before I found the in-memory connector, I used to use test containers to spin up a whole Kafka environment. That was pretty painful. This is really, really nice. So what we do now is I mentioned before we have this test resource. So I'm going to create a test resource. Yeah, I think this is awesome. I used to spin everything up in Docker Compose, the database in Kafka. And with Quarkus, you can just do it all right there. You don't have to, you can if you want to, but I don't have to put it all in Docker Compose anymore. Nope. So I'm implementing my test resource lifecycle manager. So I'm starting and stopping. And what I'm starting is an in-memory connector. And I'm switching incoming and outgoing channels. So I'm switching my incoming channels, hello in and the outgoing channels to hello out. So what this is going to do is it's essentially going to proxy or it's going to switch out the implementation. So I'm not going to fire anything off to Kafka. I'm going to fire it off to this in-memory connector. And then my test is right here. And my test, I've got my Kafka resource, right? So I'm going to have access to any of those objects. I'm going to inject my in-memory connector. And I'm going to get a sync. And then I'm going to send this in to my source. I'm going to say hi there. And then I'm going to expect this to come back in caps, right? So my sync is going to receive and it's going to, I'm going to get the payload. So the receive, get the first thing that I receive and get the payload. So when I run this test, and there are a lot of other things we can do with, with the received, right? So we can do all kinds of things that say, you know, hello, we can stream things, you know, we can loop through all of this stuff, right? So there's a lot of, a lot of things we can, a lot, a lot more things we can do than just get the payload, right? But it allows us to test really, really easy. So if you're using Kafka in your apps, it's a super simple, easy way to test Kafka. And, you know, I don't think, I think we're pretty well over. So we've taken everybody's time. So George, I know you've got to leave any closing thoughts from the Quarkus team. No, this is a great summary. The only thing I do have, like you might want to show in like a follow-up episode or something like that, there's this new mode. There was new testing mode that was released with Quarkus 3.2. We call it the Quarkus component test, I think. I have one of those. Oh, okay, cool. We didn't look at it. We didn't look at it. It's brand new. It's brand new. So basically, yeah, we're just like soliciting feedback from that because it's a very new thing. Like we have some ideas like where people might want to use it, but we really want to see in practice, like if it's useful or not. Yeah, so we, I mean, just to recap what we just went over. Here, we did the novice testing, you know, basically that was me doing the, you know, I'm new to the Quarkus environment and I'm kind of novice at the testing, you know, how can we get started? You know, how easy it was to get started. I think we demonstrated that, you know, Quarkus just amazingly removes a lot of complexity from you having to get going. It just makes life really simple. That's what I really enjoy about it. And then we went into some more of the more complex stuff with the mocking and the wire mocking that Jeremy did. And I think the Kafka and the database stuff with Pinoche was, you know, that takes us further. And you've got, oh, and you've got a component test. So we can close out with the component test. Yeah, so here's the component test. So what this does, I've got two services here, a greeting service and a tumeness service. We both ended up with some CS Lewis references this time. We didn't practice that. We did not coordinate our CS Lewis. So the base, actually I should, basic greeting. So the method, I don't need that. Yeah. What do you get going on there? That commits for that. So the component test, I have a greeting service. If I go to my greeting service, it has a tumeness service and it calls this tumeness service on greeting from tumeness. It just calls this tumeness service quote. I mean, instead of method, there's again, just some random quotes that Mr. Tumnus says from the line in which in the wardrobe, right? And we just get one of these things. So my greeting service is going to get one of those back. My greeting resource test. Not that one. This is a component test. So we mentioned in a Quarkus test, we're spinning up all of Quarkus. In the Quarkus component test, we are not spinning up all of Quarkus. We're only spinning up the Quarkus CDI container, right? ARC. So I have mocked out my tumeness service. And instead of returning one of the three actual options, I'm going to say, allow me to introduce myself. My name is Tumnus. And this way, the test is going to run even faster. Let's just give it a quick run here. And so it seems to me, and correct me if I'm wrong, George, but if you look, yes, it was super fast. I barely even got the talk while that ran. And it seems to me like that's essentially, if I know that I'm not relying on anything other than CDI, just a faster, quicker feedback loop takes even less time. Is that the idea behind doing this? Yeah. So we had a few people saying like, yeah, I don't want to start like the web layer. I don't want to start the database layer. I don't want to start the Kafka layer. I just want to test like my, let's say business logic. So yeah, that was the idea behind this whole thing. Yeah. I'll run it again just to see how it's thinking. Actually, let's say I have Quarkus running in the background. So let's break this. Let's do this. So howdy is not probably something that Pawn would say, right? Next time we have George on, I'll get a list of books that I have that are more history. All right. So we broke that. Am I still failing? Come on. It's a provider not found. Oh, well. It's what I get for grabbing the brand new feature. Yeah. I don't think it's the feature that broke it. Yeah. All right. That's what I get for it, right? I'm not used to having to know what happens when it goes wrong. All right. That's not right. But anyway, if you look again, it is super, super fast to run this test. Like it's over instantaneously, right? So there you go. Like, you know, you're not putting up all Quarkus. All right. Well, thank you very much, George, for joining us. If you see Max. Thank you. Let him know. I'll text him later. Thanks, Jeremy, for actually walking me through all the Quarkus testing for the novicec part there. And hopefully people learned a lot today. We'll see you next month. Thank you again for joining us. Bye. Thanks.