 Good afternoon everyone. Good afternoon Jeremy. Good afternoon. Thank you very much for joining us this afternoon for another Red Hat Developer Corner. We got a little bit of bait and switch going on. We actually talked about Micro-Profile and Open Telemetry last month. Hopefully you stick with us because today we're going to talk about unit testing. And how to unit test our microservices. And since Jeremy uses Corkus all the time, he's going to help me out by adding some unit tests to a service that I'm working on. So why don't we, I share my screen and we get started. Actually, so I would say first things first. So I like doing TDD. I've always liked doing TDD before I usually do TDD. But I try pretty strictly TDD. But go ahead. So I would say first things first, install the Jacoco extension. I'm also a big fan of code coverage and code quality tools. And Corkus makes it really nice and easy to install Jacoco. So maybe should we turn our screens off? Can you guys see this big enough? Yeah, you can. It's a little smaller. Yeah, if you can make it bigger, the bigger you can make it the better. You can add the Jacoco dependency here and run a build and then show everybody on the line what your code currently looks like. How about if I just run through what we got first? So I generated this project from the Corkus developer site. And all I did was I added a model. Excuse me. Can you zoom in? The font bigger? Sure. Better? Yeah, it's better. Okay. So we added a model here. Jeremy likes the repo pattern for accessing that. And we created a service so that we could add some validation to that. And then a simple resource that does just one get right here. So we're going to use some test data that we installed here. And if we look at the POM file, which Jeremy's talking about, all we have in here is rest easy Jackson and some unit testing. And we just added Postgres and Panache in order to access it. So you want me to run? How about if I run the dev first, then we'll add Jacoco? Yeah, run that real quick. In case you're listening, you haven't seen Panache before. It's an extension to hibernate. It makes hibernate even easier to use. And then rest easy, if you haven't heard of rest easy, rest easy was the first rest framework created back in the Jboss AS days. And it's still kicking. Strong handles all the rest stuff for Quarkus. So all the Quarkus guys keep talking me into going to this site after I'm running it. So what is this, Jeremy? Yeah, a dev console. So if you haven't used Quarkus, this is actually the new dev console. You may not have seen this. Even if you use Quarkus for a while, you may not have seen this one. This is pretty new. So I'm running it in dev mode. Can I just add the entry in the POM file without shutting it down? I think it'll pick up, yeah. Give it a shot and see. All right. You might actually have to tell. Sometimes I have to tell IntelliJ. IntelliJ sometimes, at least for me, sometimes IntelliJ will not pick that up without me right clicking and running the saying we import made and build. But you're going to need to run a build anyway to get the Jacoco report. Okay. So I'll shut it down and then restart it. No, just run a made and built. So let's take from the command line. You just want to build or you've got it right. Yeah. Right. You can click and run a build. I usually use the CLI. Yeah. On the terminal, I use the Quarkus CLI. If you have the CLI installed, I use Quarkus build. Just Quarkus space build. Do you have the CLI installed? Yeah. Yeah. That's what I usually do. I like using the Quarkus CLI. Sometimes I'll drop down into Maven because you don't have to go clean with the Quarkus CLI. It's got less functionality, right? Because it's an abstraction about Maven. But it's really nice. See, everything's building there right now. All right. So go and see that your target folder. And you should now have a Jacoco folder inside your target folder. There it is. Jacoco Java code coverage. And then just open up that index HTML file. I'm just kidding. Yeah. You can also just right-click it in IntelliJ and it'll choose your browser for you. And say open with somewhere in there. Open it. Yeah. Open it in browser. Pick your browser. All right. Yeah. There you go. And so there we go. You can see we've got not a lot of code coverage. So your extremely detail-oriented team lead or architect might not approve. So you don't approve. All right. Let's add a couple of other things here then and we'll see if we can help that out. What do you think? Yeah. Let's see if we can get that. Let's see if we can get that build to pass. And do you guys, if you guys are, do you guys fail your builds if you don't have a certain amount of coverage? I don't really like doing that. I think that's a little bit too much. I've worked places where they did. Well, it depends. Right. Yeah. We're to use it as a guideline, right? And go back and forth. Yeah. I think probably one of the best days of my life was when I discovered that the bug reporting tool from the test department, I could actually reassign the bug back to a tester. So that was a, that was a special day for me. You didn't, did you come on my machine? Yeah. So, yeah, back back in the day, we could reassign it to somebody else on the team. Eventually it would come back to you and then we'd reassign it to the tester and then the head of tests would come out and complain because we weren't supposed to do that. And I said, but it let me do that. So it must be, you know, all right. So all we're going to do here is we're going to add another call. So let's see what we got. Let's return book service find by ID. So I have a, I'm running in the dev mode, and it should pick that up, right? So, yeah, if I say, well, let's do the first test here. And postman. And I got all my books, but I want one with the ID three, right? So, yep. If you can expand that to that be cool. Expand this view on that. That's a great question. Zooming in is just the same as. Command option plus. We'll do it. Yeah. Hope to be better. Yeah, it's better. Okay. So, yeah, Rob's, Rob's method of testing is going into postman and doing this, but you want an actual test. So we could fail it and then say, you know, why we failed it, right? Yep. Yeah. Your test always make sure your test fail first, right? Mm hmm. So, where I had a battery of tests and they weren't actually getting appropriately, that's really good. Yeah. When I caught, when I caught myself actually doing when we were coding stuff up for this was ending the, not ending the test class with the word test and they weren't getting on. So I was getting a green, right? Okay. Got to watch that too. So Maven won't always pick it up if it doesn't end in test because I named a class test with mock. Test with mock? Yeah. And Maven didn't pick it up. So I had to say, you know, service test, service with mock test, right? All right. So I'm going to get this book and we want to look at it by the ID, right? So I'm going to go in here and my tests and all I've done here is I created a test harness with Quarkus test. I annotated it and told it with book resource to use, although that's kind of redundant, right? Because we don't actually need that. But so let's create a new test, right? So get by ID. So at test point get book. How's that? Yeah. So when I'm writing this, what are, what is all this that I'm actually looking at here? So book was given. So this is rest assured, right? Yeah. Yeah. So rest assured is a really nice library for testing web things. Certainly for testing rest APIs and endpoints. It comes with Quarkus. As long as you're using like rest easy, it's going to get bundled in there by default. Hamcrest matchers get pulled in as well so you can do all kinds of matching. It's invincible. And it's the sort of thing. I used to love going to my local Java users group for this reason that you can go and see a presentation on something and pull it into your workflow. And rest easy is definitely the kind of thing. You carve out a few hours sometimes to work with it if you haven't worked with it before. It's really, really nice. And it's really nice. You can build these really nice little DSLs, right? And so what that's saying is like given meaning, you know, given when you have a get and you can do things like add orders here, you can add cookies. You can manipulate your request or you'd like. Then you're asserting the status code is 200 and then you're extracting the body as a book. So it's going to marshal it for you, right? This other stuff you can do. You can get the response. You can pull JSON out of the response. A lot of really nice stuff. And then Hamcrest matches are really nice and useful. So you can do all kinds of assertions. You can, like you're saying, you can marshal it out. You can also assert that the body contains any number of elements or has elements equal to various things too. So really good stuff. So in the old one, I had a single test in here for Get All Books and I just said, was it successful and does it have, you know, these authors in it, right? And this one, though, I'm going to get a specific book, right? So if I look in the, what I inserted, I have HG Wells's item number four. So I should be able to do this, right? Actually, let's make sure it fails first. Nobody with HG Wells has a... Two S's, yeah. All right. And it did fail. And what's the message that I got? What did I get for a message? I expected Wells Sacks, but I got Wells. That's a good error message. Okay. You know your test is running. So if I change it and then run it again, all right, cool. So all we did so far was added a new resource. I know that it ran in Postman and now I added a test for it. And we just talked about rest assured and the functionality that we can get for matching with that, right? And that comes from Amcrest. Okay, cool. Well, that's pretty easy. That's easier than some of the other things I test, which is... So what do we want to do now? Add another... Well, we can check and see what your code coverage looks like. We can... Oh, yeah. Say you don't have to call it. So let's add the code coverage and we'll do that. Run that again. See if you've got some better looking coverage there. Okay. Well, we have the Jacoco. Actually, can we do this? Yep. I can cut and paste that right here. Well, if you didn't do a build, it's not regenerated, I don't think. Oh, okay. So I have to stop it. You've got to do the build to regenerate it. Okay. Fair enough. Because it's going to instrument your classes and stuff, right? Yep. And the only reason we're asking this, so Quarkis in dev mode, you can do continuous testing. Actually, we should show that you notice like Rob was writing these unit tests, running these unit tests, and Quarkis is still running, right? Your website is still running. So it's spinning up a version of Quarkis on a different set of ports. So your tests can run simultaneously with your code, right? Which is really, really nice feedback loop. And there is, which we can show, we can get to later. You don't even necessarily have to start your entire container up to do your tests. You can just do component testing too. So it's even faster feedback loop. So what you're saying is we could do something like this. In my properties file, I'm defaulting right now to my data source, but I don't really have anything else in there. Yeah, but it's the data source. Yeah, that little, .hgp.testport. Oh, yeah. It's using 8081 by default. But we also, up top, it says prod before you have those. In case you're watching and you haven't seen this before, prod, that's our production. There are no values set for test or dev. It's just spinning Quarkis dev services, it's spinning up Postgres in the background automatically, right? And test services do that as well. And this works on your container. You can get have action to build stuff as well. So all your tests can run using Docker. Or another, like Podman, Red Hat, sort of version of Docker. I mean, I can change the timeouts too, right? Quarkis.hgp.testtimeout. Except let's just do 10 seconds. That's a long test. That's a long test. Yeah. Okay. So I just rebuilt it. Now you want to run it again, right? Yeah. Okay. So we'll just run the test. We are not going to rerun Quarkis from the dev mode. Now you need to run build again. I did. Oh, yeah. Yep. At the terminal, I did it. All right. So yeah, check your code. I see if you have better coverage now. Kind of hard to tell, huh? Didn't look like I moved too much. Well, we got 100% coverage on the resource. Yeah. And you actually got to expand your screen and drill into that a little bit. Take a look. Drill into that resource or one of the resources. Yeah. Go into your resource now. Click on that again. Drill in again. And go into the book resource. And this is one of these things. Do we see the whole class? So yeah, what's really nice here is you see. It actually shows you which lines are covered. So everything's in green. And then if you go back to one that's kind of mixed and will show you like certain methods will be in red. And this is why I mentioned, I don't really like breaking a bill. To me, like, if you're not testing every single getter, you know, it's not that big of a deal. But those are all going to go back to like one of your other classes or one of the other packages there that's not dull. Yeah. Or got me repub. Yeah. That one's barely got any coverage. So yeah, click on that. The repo. Yeah. Just click on any of them. You should see the whole class when you click on any one room. Yeah. So you can span that. You can see it's getting implemented, but we're not using any of these methods. Right. Okay. So let's add a, let's, let's zoom in. Yeah. Zoom into that a little bit. So people can see. Do you want to get it by the query? No. Yeah. Just zoom in. So we can't, it's hard to read. Just expand your page there. Oh, still? Yeah. You see that now? Well, a little better. A little more. Yeah. Yeah. Yeah. So like this fine by query, right? That's, that's probably something we want to test, right? Certain things like, and it's also, I'm not a big believer in like, you know, you, you should trust the red hat. The hibernate guys actually wrote their persist method correctly. We don't need to test the framework that query that we might want to test that query, right? Yeah. Let's, let's do that. Yes. Cause I wrote the query. So that doesn't mean it's going to work, right? Right. That's good potential for human error, right? Yeah. Let's trust that the, that penash is fine by ID method is going to work, right? And if it doesn't, you're going to submit a bug test and red hat will write the unit test for it, right? Book service. So Jeremy, why do you like using the like service repository pattern so much? Um, it allows you to override things if you need to. Okay. I think, I mean, you can mock out, which we'll take a look at later. You can mock out individual, uh, entities, um, with penash mock. They did a really nice job with penash mock, but, um, I don't know. I just kind of like the repository pattern a little bit better. I think part of it goes back to, I like DDD stuff and you'd have a repository for your aggregate and not the other classes. Okay. So let's look at our, instead of going to post manner right away, let's go and look for this author. How's that? Yeah. I'm going to write a test for that. I think that we'll add this test down here and we'll say, um, at test void. We got some sci-fi books going on there. Yeah. I like sci-fi. Did you watch the foundation series that was on, uh, with the Netflix? You know, I got the foundation series when I was a kid. So I watched the first episode. Yeah. Didn't care for it that much because it was not like the books. So, um, uh, you know, you know, I don't know. Movies always ruin it for me. So, um, Doom movies coming out, the second Doom movies coming out this fall, right? Yeah. I read the book. I'm going to say, you know, I'll show you my age here, but I read the books when they came out. I know that's terrible, right? I read them a long time ago. I was still regularly playing Dungeons and Dragons when I read it. So it's been a while. Oh, okay. So I was a kid. We're going to look for this book. And we're going to say then 200, a get code. And then we'll say body. And why don't we, um, size. We'll just make sure that we have the right size here, right? So we don't have more than one book is one. And body. We're going to look for six. So we're going to look for this author. First, we'll make sure that it's doesn't work. So we just added all we said was, um, do the Corey Pramp. We're looking for this book and we only want one item back and we want that author, right? And we want it to fail first. Because we were told this morning, your test should fail first. Yeah, it should. Is that part of the TDD? Well, that's how you know it's getting run. So that's kind of what I was mentioning when I coded up. I had some tests not running because I coded them up wrong. Um, I named them incorrectly and they didn't get run. So I didn't see any red, right? So I ran a test in the directory to run all my tests. Everything looked like it was green. I'm like, actually it's all green, right? And then I realized that some of my tests weren't getting run. So yeah, if you get red first, you know that the test ran because it hits, right? So we, we succeeded. Why is it spelled wrong? No, I think something else is going on here, right? Because we didn't do a when. Oh yeah, okay, very good. Yeah. Well, that's kind of misleading, right? So we need to do a while you get. That's why you want to fail first, right? But we didn't fail. Well, right. So you want to code it so you know you're going to fail first, right? Right. And that's, and this is exactly why, because if you coded it correctly, you just thought you passed this test when in fact, you're not actually even running a test, right? There we go. I'm really good at failing tests, right? So, uh, and we got a good error message back, right? It says the author doesn't match expected this, but we got that. All right. So that, that's good then. So let's rerun it. But you know, there's something going on here where this is all I see when I run this stuff. I'm not actually seeing test names, right? Oh, before we look at that, let's go back and examine this. Ah, so your code coverage says I'm now covering that test. Yep. So we're good. Awesome. So the more stuff I add in here, the more we're going to get to see this in the code coverage, right? Absolutely. Awesome. Awesome. Awesome. But you know, I come from this, um, C++ background where, you know, we use printf for everything. So I kind of want to add, there's this feature that I know that exists in, um, Quarkus that allows me to do callbacks. So how about I add a callback in here because I actually want to see what tests are run. So I'm going to add a class called book resource Quarkus test before each callback. And I'm going to say it implements Quarkus, whoops, I can spell Quarkus right, before each callback. So what callbacks do is allow me to basically intercept and stick something in there. And there's a bunch of different kinds of callbacks and Quarkus. So I'm just going to do something simple here where I can make it more familiar to me, which is print stuff out, right? So before each, I'm going to do a Quarkus test method context and look at a context. And what do we want to do here? System.out.printland. And we'll say, executing get test method. Cool. All right. And I'm going to do something else here, right? Let's print out the annotations also that are on our test. So I have a little more information about what's being tested. In order to do that, we're going to do annotation. We're going to say, let's get that from the context, get test instance, get class, get annotations. And then we're going to say arrays.stream, annotations. Let's add that. And let's print that out for each. Cool. All right. But we have to add that somehow. So there's this. This is the only thing that's a little strange to me, but we actually need to make a new file here on our resources services. So we're going to add a file. And we have to give it this kind of long name, right? And it has to match what kind of callback that we're doing in order to register it. So io.korkus.test. .junit.callback.korkus.test. Before each callback, we need to put something in there, right? So our name of our test is, what is the name of our test? We've got this really long name here, right? So go into this file and say or.acme. And then paste that in there. So what's a real world example? Why would we write this callback? Well, if I had some kind of automation, I would be doing some kind of automation where I was automating the build and test. I want to be able to actually introspect the output from this and see it. If I'm debugging like we were earlier and I'm using unit testing for debugging, me personally, I'd like to see the test in here. This is kind of ambiguous what's going on right here. I know when it fails what test I ran that failed, but I don't know what tests all just got ran. I know they succeeded, but I don't know what is related to what here, right? So that's just me. I want to know that kind of information. We'll see if it actually works. Hey, look at that. I think it did. So you saw some stuff hiding in there, right? So can you see this? Yeah, that's what the annotations are. Yeah, right? So I executed that test. These were the annotations on that test. That's the actual method. And then I know that everything that followed it was part of that method that got called. Now I can introspect that and capture the test name and any annotations. Anything that might be interesting to you as a developer or if you're debugging something that broke. So the build broke and you just said, Jeremy, you know you work on teams where they kind of chastised you for breaking the build. But how do you know which, you know that this test failed, but you don't know anything about that test, right? So I just wanted to capture something that might be interesting to me for that. And then we can capture all kinds of interesting information using callbacks. All right, cool. What about an integration test? You want to create an integration test? Well, there's a couple of different types of integration tests, right? So one hand you're doing an integration test here because you're actually going to a database and pulling stuff out, right? Yep. And you can also, you can mock out your Panache objects. So you don't have to do that. This is one type of integration test. There's also the ability, you can test your jar files and you can test your native compilation files. And so when you have the IT test, you have an IT over there in your side. That's going to actually test your native build. So you need to build that first, right? But you're going to... I'm just going to show you how easy it is to actually add it. So how about book resource IT? Yeah. And part of the reason this is... Oh, sorry. Go ahead. Go ahead. Part of the reason this is an integration test is like, you can't mock something out in a class that's already compiled, right? So if we compile this down to a native application, there's not going to be any mocking of anything. You're going to have to run an integration test. You're going to have to have a Postgres database spun up. You're going to have to have Kafka spun up, whatever. And the Kafka's Dev Services will run under your test as well. Make that a lot easier, but you still have to have those things in place. Yeah. So you're going to have to run a separate container with Postgres in it, right? Yeah. It's a little spinning up for you, but... Well, I noticed that when I'm running tests here, stuff is actually being spun up in Docker. So if I open Docker desktop, so what's going on there? Yeah. So it's using test containers in the background, spinning up any containers you need, right? So you've got Postgres. It's going to spin up Postgres. If you had Kafka, it'll spin up Kafka, whatever. Okay. So it ran the test and now it's going to wait for it and it cleaned it up by itself. Yeah. It's really nice. Excuse me to get out of action, too. All right. So what we did here was we added some resources and instead of just testing via Postman, which was nice, we added the actual tests. So they're repeatable and we can do them during the build, right? And then we demonstrated some... rest assured. And then we demonstrated some hamcrest capabilities here in order to do pattern matching, right? Yep. And we added the capability to do some callbacks and we showed you basically how quick it was to create just a degration test, but we also talked about, you know, in order to do that, you really have to build it and have something separate running, et cetera. In order to call that. Cool. And we did all that. Oh, and we added Jacoco and all we did was add one thing to the POM file. So this makes, like, really, really simple to get going doing our unit testing here, right? That's cool. All right. And we added a couple things and properties just to show that the port can be changed. Right. And that was it. All right. So I'm going to turn it over to you, Jeremy, because you actually have a lot more complex stuff that you're going to demonstrate for us rather than Rob doing the easy bit. Okay. How's that? Why don't we start with some panache so I'm just talking about that, right? Mm-hmm. Grab that. So a big fan of mocking stuff out, right? So can you see my, can you see my, there we go. Yep. You got to make it bigger. Yes. All right. So hide that little noise. Okay. So this is, I just started Quarkus down here in my terminal and I am running this app. Let's come to local host. Let's say local host A, A. Let's say hello. All right. So what is my app here? I have hello. And then if I add a name here, so I'll say hello, you are. Now we say hello, you are. Let's say hello, nation, right? Hello, man. We had a book theme gone on there. So we had a book theme going on. Yeah. Hello. And now I'm going to say hello all. So when I was doing that, it's popping this stuff in the database. So it's grabbing the name and it's creating a greeting entity and putting that in the database. Let's take a look at the code over here. What this is doing. Source made Java. Let's say the... There it is. All right. So what this is doing, the path hello here. I have two different resources, an active record greeting resource and then I have a repository one. And I'll just talk about why here in a second. But what I'm doing, this is my get hello, taking a query param, right? It's pretty obvious what this stuff does. I'm just returning hello if it's null. And if not, I'm creating this greeting object, dump it in the database, and then returning hello with the name, right? And then when we do the all, I'm just returning greeting list all. If you haven't seen Panache before, we mentioned it earlier, Panache is an extension to hibernate and it adds all of these methods, both in an active record pattern like this where we're working with the objects themselves and in a repository pattern. Now, when I want to test this, one of the things we typically often do when you're testing data, right? You have to figure out how to get data in and out of the database for your tests. So let's look at this. This is an active record greeting test. And if you notice here, I have a before all and it's transactional, which is just saying I need a transaction to talk to databases. This is going to use the containers in the background like you saw a second ago. And what I'm going to do here is, first of all, I'm deleting anything that's in the database and then I'm sticking one new greeting in here, right? We're stuck on a Winnie the Pooh theme here. This is, I'm going to put Christopher in the database. We had Eor and Piglet and stuff earlier. So this test is going to call the hello endpoint. It's going to expect hello because there's no query parameter with a name. And then on all, it's going to expect there to be Christopher there, right? Because I've put that in the database. So let's just run this test here really quickly. And we'll see here. So I'm passing, right? And so what we can do, we can add more of these if we want. We can do that. Now, one thing I don't like about this is this is an integration test, right? We're going directly to the database and we have to have a database running. So let's look at another way we would do this. So let's take a look at this. And I call this another active record creating test. So it's using the exact same pattern as the exact same pattern, except I'm not going to go to the, I'm not going to round trip to the database. What I'm going to do is I am going to call a notch mock. And what you need for this, we do need to add one thing inside our palm here. We need to add, let's just go down here. So I've added Panache Mock, Quarkus Panache Mock extension. So it's just a test scope dependency, right? So what I'm going to say, Panache Mock, I'm going to mock the greeting class. And then I'm going to say, when LooseDoll is called on the greeting class, return three different greetings, right? Poo, Tigger, and Eeyore. And so when we get hello all, I'm going to say, I'm going to verify that it contains the string Eeyore. It'll also contain, we can do multiple ones here, but I'm going to value it at least it has Eeyore. Another thing I'm going to do, because I've mocked this object, mocks always return a default value. So when I call the actual count of how many objects are in the database, it's going to return zero, because that's the default, right? Now, you can override and the reason for that is it's not really storing these in the database, right? It's training that mock to say return this many values. And if you used to do this the long way, it used to be a lot longer. This is a really nice fast way to do it. Now, you can override that. So in this method, I'm doing the exact same thing. I'm mocking it, I'm returning three of these things, but then I'm telling Machito to actually call the method. So if you want to override an actual method of your class, you can do that. So now I'm going to call the real method and it's going to say there's one, right? I'm putting one thing in the database. So let's run this thing. And so this is passing, but like one thing we can notice, so I'm putting Christopher, Christopher Robin here is going to the database. So realistically, if it was really calling the database, it would say this would pass, right? This isn't going to pass because it's not, it's bypassing the actual call to the database, right? So it's going to fail here on test mocking list all. Right? Yep, as expected. So it's failing. So we're not really seeing that. So that's how we can mock out Panache objects. We can do any of the methods that are on a Panache object, so any of the stuff we want to do. We want to do our queries, right? We can say, greeting, you know, out, delete, list where, you know, queries in here, find. We can put fake queries in there and return whatever we want. So I think that's very nice because then you're not testing, you know, you're not testing the library. Don't test the library. Red Hat wrote it. It should work. So what's the difference between, you know, and kind of mocking for all the tests versus any, you know, an inject? Ah, all right. I'll jump to that in just a second. Let me just show this off. For the repositories, I can just inject the mock. So anything that can be injected, I can directly inject a mock object into the test. So I don't have to say, and then you just still say, whoops, darn it. I don't want to see my code commits. Okay. So I can do the same, do the same thing, and then I just train my mock right here, right? I don't have to say panache mock. I can just inject the mock. It grabs it, but otherwise this is effectively, this is the exact same test. All right. Now, I'm not putting data in the database ahead of time here. This is a kicker to why because you can't, that's a static method, and this, so this is a static method, and injecting classes can't be static, right? So in that sense that you would just drop down and use, if you wanted to round-trip the database, you could just use the object directly and test that way. So I could do a before all or before each in there too? You can't, you couldn't put an injected class. You can, you couldn't put an injected class in there though. Okay, so injected classes can't go in there. So let me see if I can, let's get my where is, let's stop there. And you mentioned, you wanted to see what the difference between having a mock for the entire project. So let's go up to LS and say. Yeah, because sometimes I want to do like a, you know, inject the mock, but do a before each test to reset the, what I'm doing versus all right. So let's look at this with Clarkish fired up. All right. So now this app. You guys, you guys can't see this. So this app is going to be a little bit different. This is this one here. So if you see that we've got a greeting resource again. So let's go back and check out our application. Let's say hello and we've got this time we're going to rotate for some random hello's right. So if random hello in random languages, I've also got and not hello name, but I've got a quote endpoint. And the quote is going to do the same thing. It's going to have some random quotes, right? So we can refresh and we'll get these random quotes and by the person who said them. We also have in here a class called, and we can see who the cast members were, right? So we get random cast members. All right. So we've got three different services that are all wired into this object here. Let's take a look at this object. So my greeting resource appearance presentation mode. All right. So my greeting resource, I've got a greeting service, a quotes resource and a cast service. And for all of these, I'm just calling a random method to get one of those back if you want to see what's in there. So for instance, let's take a look at our random cast member, right? A random cast member, I've got a number of one, two, three, four, five different cast members, right? I'm just returning a random one of those. So if we come down here for our test, let's take a look at a test with a greeting resource test. Our basic test here is going to call hello and it's expecting a random greeting. Well, let's go back and look at my greeting service. So my greeting service does not return a random greeting, right? So it returns hello, hello, hello, right? Down here, I have a mock greeting service that returns random greeting and this is using this mock annotation under the covers it's using a CI CI alternative. It's a you can define your own annotations pretty easily inside the Quarkus framework inside CDI. So this is encapsulating alternative priority and dependent CDI annotations into mock. And what this means is every single test inside of my test directory is going to get this installed instead of the actual greeting service. So I have multiple tests here. I've got a greeting resource test. I have a greeting resource mock test, greeting resource with alternative test. And all of them are going to get this exact same object. So let's take a look at what this test looks like. So I have a quote. I'm checking a quote. It's still going to be a random quote. So I'm going to assert that I get a random greeting for my hello endpoint. And then for my quote endpoint, I'm just going to use one of these matchers. I'm going to import this statically too. This is the Hamcrest core matcher. I'm going to get any of these. I'm just making sure it contains the string Dude, Mod, or Walter. They account for all of our quotes. And in the cast endpoints, I'm going to make sure it contains any of Dude, Mod, Donnie, Walter, or Jesus. These are the ones that are going to come back randomly. But this is going to be overridden randomly. So let's take a look here. And we'll run generator test. So this is coming back false. We want to make sure it was correct. So this is coming back from my mock object. These are not coming back from my mock object. These are coming back from actual services. So let's take a look at one of these others greeting resource with mock. So now I'm going to inject a mock. In this case, I'm still going to have my random greeting message because that mock is installed globally because the class itself is annotated. In this case, the class is not annotated. This mock is only going to be available inside of this test. So in this test, I'm going to get my annotated class mock here. And then here I'm going to get a quote end point that is not part of the ones I would normally return. It's only part of this mock. And the one that I'm returning here says sometimes you eat the bear and sometimes well, he eats you. If you remember Sam Elliott saying that, he's the stranger after ordering a sasperilla. So now my cast endpoint is still going to call a real service and it's going to get one of these random ones. Everything works there. So just to recap what happens here, I've got a hello endpoint that is annotated with mock, right? Where is it? Hello endpoint, it's annotated with mock right here and so that's what's going to be installed in all of my test classes. And then I've got quote endpoint test that I've mocked locally and trained to return the quote about the bear and it's going to contain the substring and none of my actual ones would. And then I'm still getting my service here. So that's one way we can that's another second way we can use mox. Let's look at another one here. So I've got an alternative cast service and this one I've annotated with alternative. So it's not installed everywhere. But I've got a Sorry, that's a thing. TDI thing. So I'm implementing something called Quarkus test profile. What this is going to do is it is going to make some things available to my class. There's a lot of things there's a lot of things you can do inside of Quarkus test profile. We'll see another one here in a second with Kafka. What I'm doing is I'm getting the enabled alternatives and I'm returning alternative cast service. So in this particular test. Which is it where the greeting with alternative test right so. I've got I've annotated this with that cast profile. So I created that profile that says we're going to use a different version of the cast. And so this time I've got my markets installed globally and now I've got a cast endpoint and I'm expecting the big Lebowski right because my alternative go back here. My alternative cast service is returning cast member David Huddleston who played the big Lebowski himself but he's not part of my actual regular being right. Let's come back and there we go. So now we'll get the big Lebowski here. So that's three different ways we can stub out or mock out various objects that we need. That way we don't have to round trip with the database. We don't have to interact with any of these other services if we don't want to right. So why would I want to spy on something instead of mocking it? So a spy presentation mode. So the reason you would want to spy on something do I have a lot of spies. This is a slightly different project. So in this case I have a greeting service that has quotes from Narnia right so it has it gets a Tumnus service in here. Actually my greeting resource here says hello but I've got this service called a greeting service that gets sometimes it has a method called greeting from Tumnus and then it passes over a quote from Tumnus right and so Tumnus has a handful of quotes here. The reason I lost my spy so what we do with a spy is you would here let's just open up one of these other ones we'll grab it real quick. So greeting resource test. What you would do with a spy is you want to just find out that a method gets called. So let's say at inject spy and let's inject in this case we have our cast service right. And so when I come down here to cast endpoint what I'm going to say is let me get this big again. So my cast endpoint now I'll say Machito verify cast service random cast member. I'm going to say here I'm going to I'm not going to Mach this out I just want to know that it gets called one time so let's run this and so now oh we failed which one failed test I didn't did not inject a spy inject spy cast service cast service random cast member Mach some method yep so I wrote that wrong so you want to verify service times one okay so there we go now we'll run that again if you fail you know it's getting called correctly right so what I'm verifying now is that my cast service was called one time so what I want to know and a lot of times that's like what you want to know I don't really want to go to a full integration test but I do want to know that this method got called right and if it's like let's say it's a void method you're not necessarily going to get feedback right so if I was calling a void method on another class or I was just sending something off to do some other logic I wouldn't know if that happened or not right and so that allows us to test a void method so a spy knows that we got that method called cool so what's this wire mock thing you want to do wire out at least let me show one more thing we can do we can set up as a test profile first with Kafka and then I'll jump over to wire mock that that is a pretty pretty nice thing where do I have did I not bring my coffee down whoops okay let's do wire mock first grab coffee so wire mock if any of you guys use wire mock wire mock is essentially going to spin up a server that's going to allow you to mock out rest endpoints or any kind of connection endpoints let's see out here let's go up and we'll go to quarkus testing spy on quarkus and key equals we're recording this normally I'm going to regenerate my API key because I don't have it no it is not I key equal at an environment variable before I started this right so now my now everybody's be hammering my API key it's alright so let's see what we have here let's say local host so I was thinking this weekend or actually tomorrow the premier league starts back so let's see what game is tomorrow right this is fixtures I've called this I've called my own service we can see it's at turf more and it's Burnley versus man city right so Burnley man city playing at turf more is our game tomorrow so let's come over here and see what we're doing so what we're doing in this case is I'm using a football football fixture and I have a quarkus rest client here I'm injecting the rest client adjust my view I'm injecting the rest client and then I'm just calling the rest client with these parameters right that I need for this particular call the way the rest client looks in quarkus this is an interface so quarkus will build this out for us I'm registering a rest client this just points to my configuration in my application properties file it's got the base URL things like that and then this is a custom header that this particular provider is required and that's the football key that I got from the command line and then I'm passing this over to fixtures so I'm just making a pass through call for this so let's say I want to test this to make sure I wrote it correctly because I've got like some custom headers here I've got some query parameters like I could have written this incorrectly I mentioned before we don't want to test the library so I'm going to trust that red hat knows how to do the register rest client piece but I'm not necessarily going to trust to know that I got my headers correct or that I don't have some extra headers or that I they're going to get me you know they're going to cause the request to be bad or that I've got my query params correct right so I want to make sure all that stuff's correct so when I test this I'm going to come in here and I'm going to use wire mock and what wire mock does bring up my test class there's two ways I can test this there's my API football service this is the one I'm going to want to test with wire mock so what I'm going to do is I'm going to inject the rest client so I'm going to use the actual code I wrote and I am going to call that and then I'm going to assert that my this doesn't come back null and then I'm going to assert that I get a different response so if you noticed in that XML here in the JSON here the game is at and you turf more right so what I'm going to test for is where did my class go I am close my so what I'm what I'm going to test for I'm going to test for a different venue so I've changed my venue I'm going to test that I get main road which is where Manchester City used to play not where Burnley plays right and so the way I do that I had that Quarkus test resource already looked at that so what I'm going to put here is that I have another Quarkus test resource and in this case I've got a wire mock server wire mock I'm going to start this up on port 8089 and then what I'm going to do is I am going to capture every call every proxy call and I'm going to send it back to the actual URL unless the URL looks just like this in which case I'm going to return a response with you know this header and this value that's just my test values class right and in this value it's just like the other one except it says main road right and so that's how I know I have got that my that I'm going to be using my stubbed out data right because it's going to say main road not turf more so if I if I'm round tripping to the server I'm going to get back the actual correct venue right if I'm doing this my JSON is going to come back correct but this value is going to be different and so we did I got my value back differently and so that lets us test to make sure that I annotate everything correctly that I have my API my API football service is set up correctly now inside of my Premier League standings like my the rest thing that fronts this I don't necessarily want to do that right so you know what I'm going to do there is I'm going to inject a mock so in the other test it said inject just the rest client I was actually using it now I'm going to inject a mock for rest client and in my setup right I'm just going to say when get when call this then return and I call mock football response right so I'm going to return a mock response because essentially when I'm testing my rest endpoint I don't really care what happens in the background right I just want to know that I'm properly passing this data over expected two different ways two different approaches to testing but both of these are this is certainly a unit test the rest client you know testing a rest client and actually it's a unit test for the rest client right because I'm spinning up wire mock I'm not actually integrating with the real API although it's kind of an integration test because I am calling another party and then I think let me want to jump into one more thing what do you want to show now? the Kafka had another instance of IntelliJ ah darn it yeah my Kafka one so let's go do I have Kafka here I do have Kafka here oh there it is see how it gets so Kafka is testing Kafka so I'm going to have a really simple hello Kafka resource I'm going to have a really couple of interesting tests here didn't mean to open that in alright so this is my test this is a really simple Kafka class all I'm doing I'm listening for a topic hello in and then I'm sending some the exact method that comes in I'm doing a little transform here where I send it to uppercase and send it to the topic hello out but I don't want to have to spin up Kafka to run my test so the way I can do that is let's open both of those what I can do is the same way we saw before with a test resource I have a Kafka test resource same methods I'm implementing this uh Quarkus test resource but start and stop and I've got this thing called an in-memory connector which is part of small rye and I'm switching incoming channels hello in to in-memory and outgoing channels hello out to in-memory so what that means is I'm not even going to talk to Kafka small rye reactive messaging library I'm just going to grab this hold it in memory and send it back in to the place that's listening for it and I can do all that in Quarkus without having to start a Kafka instance yep and so now what I'm going to do is in my test I'm going to inject the in-memory connector it's not a mock it's an actual messaging connector and here I'm going to call I'm going to create a source and a sync for hello in and hello out and I'm going to send hello in and then I'm going to assert that it comes back capitalized from my sync let's run this really quickly and it's coming back out quickly so this just goes into the in-memory connector my class does its work gets its message like let's do that let's say a lowercase or again this time we'll fail if we're expecting it to be an uppercase there we go so now what we look at is this way I don't have to spit up any of these dependencies I can really do a true unit test it looks like we're right over the hour too since we're over the hour anyway you want to show there's something new called the component test I can point where is my component test I have a component test I can remember where I put my component test yes was it under component test alright here we go yep so this is relatively new to quarkis since version 3.2 yeah this is a pretty new test so what component test is doing we mentioned earlier quarkis test is going to spit up an instance of quarkis on a set of different ports now you don't always need to spit up an entire instance of quarkis what we're testing is cdi beans I don't need to do that I can just do a quarkis component test and what that's going to do is it's not going to spit up all the extra stuff it's only going to spit up my cdi container which is called arc and so in this particular project I've got a greeting service here and the greeting service presentation mode again the greeting service has a tumnus service injected and it has this method called greeting from tumnus and then we call tumnus service quote right and so from tumnus we will get one of these three quotes and those are all just cdi beans these are all cdi beans right so application scoped cdi bean so I've got this tumnus service I have this greeting service and now I'm going to test them only by testing cdi beans so what I'm injecting the actual greeting service and then I'm injecting a mock tumnus service I'm telling the mock to always return this one allow me to introduce myself my name is tumnus which is not one of the although it makes a lot of sense it's not the one that we actually would return so let's do this let's say run and that's passing so I've mocked this out so what this lets me know is I'm actually this I've mocked I'm not testing this right now so I've got a mock for it I'm testing this and I want to know that it's going to correctly pass through one of these greetings and so I'm getting this example like earlier we were looking at spies so we could say like injecting spy right and then this is what we would say mocked verify one on this service did I mess it up again so now I'm just going to verify that it calls this right another way we can run this I'll point an exception we did that in another class I won't spend time figuring out what I typed incorrectly there but there's different ways we can do that right so the idea here is like if I get data back it's data that I'm controlling and these are just static stuff right but like let's say if I was going to the database or if I was interacting with other stuff I was doing some business logic it's just easier for me to just mock that out and get that back cool so where is all this code yes so all this code is on github.com developer corner stuff so let's go over here developer corner stuff right here probably should clean these repositories up we'll have to figure out a better way to store repositories but we just created this organization and we've got a site here so we'll have links to download all this or you can just go ahead and grab the stuff right now and you can always find us on here too so if you need to find us there or you can always reach out to us through social media or emails alright thank you very much Jeremy and thank you everyone for joining today and hopefully we get to see you again next month oh who are we going to have next month so many specialists going to join us yeah it's not it's not going to be us in fact we're just going to be hanging out watching yeah I think somebody from the quarkis team so we'll look out for that alright thank you again and hope everyone has a great day thanks a lot