Conf42 Enterprise Software 2021 - Online

Making the Jump to JUnit 5: A walkthrough of migrating code from JUnit 4 to JUnit 5

Video size:

Abstract

When it comes to our software, we talk very adamantly about upgrading the packages that support it and debate heavily on the cadence of those upgrades (e.g. monthly vs as we code). We treat the JVM versioning the same way: debate heavily on the cadence but generally agree that it should be upgraded throughout the lifecycle of the application. So why do we treat our testing frameworks any different? Aren’t they as critical as our application libraries and our JVM versions?

Of course! Some could argue even more so than the application libraries and the JVM versions. In the application of Test-Driven-Development (TDD), the first toolset that one touches is the testing framework and it would make sense to upgrade it often, given this is where TDD developers start.

Summary

  • Jonathan Meek talks about making the jump to Junit five from Junit four using the spring framework. Meek is married to the most talented agile coach Baker known to him. Currently training for his first half marathon.
  • Test frameworks are usually the last thing to be upgraded into those code base. Junit five represents a major version shift and reorganization effort by the Junit team. Can't I use Junit vintage? You could.
  • With spring framework, you want to make sure you have Java eight or higher. And I want to show off some of the features that are new to junit five. Now you're able to do many extensions where in the past you had to choose between a singular runner. And parameterized test allows you to write programmatic tests.
  • The application is a simple rest endpoint that allows us to be able to do a couple of things. We're using mock MVC. The first place we're going to start is with the controller test. Then we'll work into the service and whatnot. At this point it's probably going to scream about a lot of different things.
  • Move from junit four to junit five. What you have to do instead is actually a lambda function. So right now you can see on line 34 should return all coffees when hitting default resource with get. Everything again works.
  • With this app I have this Testdata CSV, right with those CSV file source. It returns a single copy by the coffee's id. Instead of nine tests you should see eleven tests when we run this. We added two more tests by being able to use the parameterized test.
  • Thanks to my teammates on the tax commons at the Home Depot. Jeff Anderson who gave a lot of feedback on this talk. Jonathan Davis helped me with Obs and getting this all pulled together. Lastly, and not least, I wanted to give a shout out to dinner bursary. Without him I would definitely not be doing this today.
  • All right, give me a second here and I will actually pull together my twitter handle as well as where you can find the code behind all this awesome work. As far as the GitHub repo, if you go to GitHub. com 61, you'll find me.
  • All right, so GitHub. com ehoc 61 migrating four junit five so you can find the code for all this. Feel free to reach out if you have any questions, concerns. Be safe out there and looking forward to when we're all able to be back together and in person.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
You. Hello and welcome to my talk concerning making the jump to Junit five from Junit four using the spring framework. My name is Jonathan Meek and we'll go ahead and get started. So a little bit of background on myself. I've been an active Java developer since 2010. The oldest version of Java I've ever worked on was Java 1.6. I was doing this in the process of working on network provisioning software, which was a lot of fun of currently training for my first half marathon. Originally this was set for March of this year that's been postponed, so I'm just going to continue training. I have two cats, Deacon and Reina. And as you see here in the photos, on the left hand side is Deacon, on the right hand side it's Reina. So the other part is I'm married to the most talented agile coach Baker known to me. So she currently does consulting with executives. But there's a lot of shop talk that happens and she's usually coaching me on how to be a better developer. Here in the little corner here, you see this wonderful little treat she's made. It's peanut butter Reese's cup. So that's just a little bit of background onto me. But let's go ahead and jump into what you came for, which was understanding that migration path for Junit four to junit five. So before we talk about that, from my perspective, I believe that there's a deeper problem that we're not talking about. Test frameworks are usually the last thing to be upgraded into those code base and I think it comes from the idea of we want things to continue to work. And kind of a side note, Junit was originally released in 2006 and I think as those comic illustrates here, right, this is our attitude. We never touch the ancient code. But the problem is when it comes to our testing frameworks, especially for those of us who are practitioners of TDD, this should be the first thing we should be looking at and we should be considering how to upgrade these things because these are those tools that are giving us the cadence that our software is working as designed and intended. Another aspect, something we're not talking about either. So I pulled this from last year's presentation track for a developer conference. Notice that there arent a lot of things talking about migrating beyond Java eight, the SE eleven developer certifications and discovering modern Java. A lot of things indicating towards that path but nothing around those frameworks. Now granted, this is the code Java, but when I looked across the whole programming track, there weren't anything. And to put it into context. This was actually the conference I just recently presented at Devnexus last year. And when I was talking at that conference, that was something I pointed out again, I think as a community, we have to start being willing to talk about not only the cool frameworks we're using to develop our code and the cool features of a programming language, but also those testing frameworks that we're looking at as well. So, first question, it's just a parentheses swap out, right? No. Junit five represents a major version shift and reorganization effort by the Junit team. It actually breaks it down into three main projects now. So you have the Junit platform, so that includes the test engine API interfaces, as well as the Junit Jupyter, which contains the actual implementation. So again, doing best software practice of decoupling the interfaces from the implementation so changes can be made in the future while not breaking compatibility. And then Junit vintage, which supports running Junit three and four tests in junit five. So if you're listening to my last comment, there's another question. Can't I use Junit vintage? You could, and I would say why? Because it's kind of kicking the problem down the road. I understand that there are needs for older code bases where we can't exactly go in and dive in and make those changes, but I would press that. We may need to reevaluate that. And also, personal experience, it's been that Junit vintage hasn't worked for me. Usually the testing fails, it does something weird. So I would say that Junit five can be introduced to an existing code base, and also, if you're going to do it into an existing code base. Right. You're going to have to be mindful of the fact that you're going to make some changes there. With that in mind, you'll see some clarity and some changes that happened in the annotations. So again, this is kind of why it's not an easy one to one swap out rate. It's. There were some updates that were made, and to me makes it more clear. You can see that the at test annotation stays the same, but you can see for some of these other ones, they've become more specific. Right. So before all versus before class, and then the before becomes a before each and after and after each. My favorite one is probably the TDD ignore becomes a disabled for me. That's a little bit clearer in my head. So you can see where at junit five they were trying to aim for conciseness behind what they were saying and what they were doing. Another thing you'll see is the packages name no longer is test located at that level. Again, it goes back and reflects the changes we saw earlier when I said that there was a separation of between the implementation and the interfaces. So you see this Junit Jupyter API test, and then same with the assertions, again going back for that conciseness and that clarity of where things reside. So now that we've kind of talked about the bigger pieces, let's kind of talk through what does an upgraded path look like? So in this example we're going to talk through with spring framework, with some of the other frameworks that are. But there they have started going to having Junit five be the default on new projects. So we won't go into detail that, but we'll talk at least here. So at least with spring framework, right, you want to make sure you have Java eight or higher. Again, this has used some of the lambda functionality behind it in order to do this, and then spring framework five or higher. So looking through the spring framework setup, Springboot 20 eight release is actually the first time you see Springboot five. And so you want to use that version or higher. It actually became default in spring boot two four. So in this example I'm actually going to show it using the spring two four, because that's easier. And I want to show off some of the features that are new to junit five. In that process, you want to make sure you upgrade your dependencies in your palm XML, and then you want to swap out the following bits, right? A run with becomes an extend with your spring runner becomes a spring extensions class, and your before becomes a before each. And also if you're using Makito, your junit runner class becomes a Makito extension and a keynote with the runners and extensions. Kind of the cool thing is now you're able to do many extensions where in the past you had to choose between a singular runner. I actually ended up using this on a project recently where I needed to add in the Makito extension. So I was able to do an extend with Makito extension class and it worked perfectly. No problems, no issues. So something to keep note. And then also that last part of you can flip to the earlier slide where it says the TLDR diff part two where we talked about that packets guidance. And again when we demo it, we'll actually walk through that. So not only is the same functionality there, but there are a couple of cool features that I find extremely helpful. The at display name allows you to add a human readable name to the test. I find this great for developers who may not be as experienced in the code base to be able to identify what exactly has gone wrong in a test. In the past when my team has done those things, we've had to come up with some sort of weird naming convention of should do this, win this, then kind of pattern in the method name. So this allows us to just be able to add something that's a little bit more readable and also can potentially allow for inexperienced developers, any of your scrum masters, to kind of take a look and understand where has it failed, especially if they happen to be reviewing test case results from a given setup. The other two that go hand in hand is parameterized test and those CSV file source. The parameterized test allows you to write programmatic tests where multiple inputs can be passed and tested individually. The CSV file source allows you to point to a particular place and say, okay, I want you to use this file to generate and pull in the information behind that. So at this point we're going to do some live coding. I put that in air quotes because of the fact of I've already done it and I can actually switch branches over into the junit five, but I want to at least try my best to go through it. So without further ado, we're going to pop out and get started. Okay, so to kind of show off, I'm first just going to run the gradle. Sorry. I'm actually using maven, not gradle on my work setting. I usually use gradle, so I figured a lot of people are probably using maven, so I figured to stick with that. So I'm just going to do a maven clean test, prove everything works as it is. Right? No black magic here, right? Because I feel that's important when we're talking about, hey, I want you to go do this thing right. All right, cool. So it runs through all the things, tells me everything's good, has nine successes. Okay, so what I'm going to do is I'm going to change this, but for two four, and I believe if merge serves me correct. Let's see, do I got a one? No. Okay, so we'll just go with two four for now and helps if I use the right keys. All right. And yeah, sure, we will go ahead and do that part. Now. At this point it's probably going to scream about a lot of different things. So the first place we're going to start is with the controller test. And we'll work through the test first, make sure everything looks correct. Those and then we'll work into the service and whatnot. And then I'll at the end do the full set with everything converted over to junit five. All right, so let's start with the controller test. As you can see, all the assertions and all the things arent screaming a little bit. So what we'll do is for now I'm actually going to remove the imports for the time being. And as a side note, with the application itself, this is a simple rest endpoint that allows us to be able to do a couple of things. So just real quick I'll show you got a simple controller of coffee, one of my favorite things to drink. Unfortunately because of the time of day I'm not drinking one right now, but it's one of my favorite things. So I have an endpoint where I can get all the coffees. I can get a coffee by its id and then I can get the best rated coffee. So that's what my testing does. And all this is backed up by an h two in memory database just for simple simplicity and whatnot. So this is kind of a general view of what the application looks like. All right, so we change this to an extend with and let's see if whoops helps if I don't, but the buttons. I'll let the system give me a hand here a little bit. All right, change that runner into an extension as I said earlier. And again, the system is going to help me a little bit. I'm also going to go ahead and delete the not needed piece there. Okay, so keep scrolling down. And in this case, again with the control treat. We're using mock MVC. All right, so let's see. I want to do that import. All right, cool. All right, let's see. What's it mad about? Okay, let's scroll down the assert. So this needs to be versions to make this work because it moved from assert to assertions in GNH live. All right, still not happy with that. Let me try and import. Yes, there we go. So I'm actually going to use the junit Jupyter API. All right, cool. Now everything looks correct here. Let's scroll back up. All right, cool. Nothing's yelling at me. Everything seems to be okay. All right, so I'm just going to hit Ctrl save real quick. All right, so that one is good at this point. Now I'm going to move into the service. The service may be a little bit more tricky because I know that there was one thing I had changed here with this before. It may yell at me a little bit either in the runtime and whatnot. We'll wait and see what happens here because at one point in the development of the code, it was demanding that something be static. So just as a heads up, we may run into a little bit of a bump here. All right, so I'm going to go ahead and delete the things that it's yelling about for now. Again, I could probably walk through and type and correct them, but we'll do this last one because it's just simply adding that and oh yeah, the Jupyter API assertions. There we go. That's correct. All right. Deadwidth right now, imported the right thing. It's going to be like, what is this? As I said earlier, it should change to an extension in this case. I know that with Makitoj junit runner, it changed name into Makito extension. So we do that. Okay, so we see all those mocks and the jacks. Okay. And we'll try before each helps if I import it. Yes, it's imported. All right, let's do that. Cool. All right, so the thing here that changes, right, is in junit four, you're able to do an expected that's no longer the case. In five, this particular ability and annotation does not exist. What you have to do instead is actually a lambda function. So this is that first place where we see something that happens. So we'll do an assert throws. And with that assert throws, I tell it. Okay, here's the expected type. So I'm going to tell it exception class, I'm going to do a comma and this is where I insert my lambda. And what I'll do is actually the command I care to call or sorry, those method I care to call. So it's actually this one. So I'm just going to use the right keyboard bindings, paste it in. All right, cool. And also get rid of that. So kind of the cool thing is you now get rid of the wonderful error, your id or editor yelling at you and saying, hey dude, this is never used. You don't do anything with it. Right. It actually gives you a purpose and allows to avoid that problem. All right, let's see. Static import of the assert throws. Try that again. All right, it's just going to be mad at me for a second. I think I misspelled something. That's usually my biggest problem. Those we go nice. Now everything looks nice and pretty. So let's go back up here to the top, make sure we're not missing anything. Okay. So it's going to tell us get rid of line eleven. All right, cool. So now I hit save. So next thing I'm going to do is just going to rerun my test. All right, cool. Everything again works. No problems. All right, so all I've done thus far is just move us over from junit four to junit five. But I've not done any of the new features around that. So what I'm going to do is actually go into the controller test and I'm going to show off the display name. So we'll take this first one here. So when I do at display name and it gives me this option, I am able to define that human readable thing. So right now you can see on line 34 should return all coffees when hitting default resource with get. So right now what I'm going to do is quickly kind of come up with a kind of standard, so to speak, treat, I would think. Okay, so return all coffees. See, I want to do that particular endpoint and then I expect treat to be actually get and then that endpoint. And then, okay, I expect that to be a 200. Okay, so you can see here, I'm kind of using a quick shorthand to be able to communicate what the expected output and ability of it is. Right. And when I run this. So let me do that and we'll do those maven clean install. Actually, I wonder, I'm going to try running, doing the run test here in visual studio code. Because if I do that, it will probably show it more clearly in its test runner results. All right, looks like it completed. I pull this open. All right, see, so right here in the test report. Right, you have return all coffee. Use the dash. The get 202 hundred. Sorry, get default endpoint 200. Okay. Right. What I told it to be here. So again, just one of those things that helps with readability, helps with some clarity around what it is that you're looking for. All right, so next thing I'm going to do is we're actually going to try out the parameterized test. Again with the parameterized test, what we would do is we would just give it a list of parameters and give it a csv. So in this case, I'm going to cheat a little bit. I'm actually going to go ahead and jump over into those junit five completed setup and we'll walk through it and I'll explain how all those pieces come together. It will save us a little bit of time here. So let me pop here into the terminal, check out five complete new computer and I forgot to put treat little keyboard shortcut. There we go. But all right, cool. Now I'm actually in the right place. So when I scroll up you can see here where I've given all the display names, tried to put a put, tries to do a put on this resource, get a 405 method not allowed, right to provide that information on the display name. And actually the test I'm looking for is in the service. I keep saying the wrong thing. All right, let's see. Here we go. So it should return a single copy. It returns a single copy by the coffee's id. Now with this app I have this Testdata CSV, right with those CSV file source. This resource starts off looking at the test resources folder in that class path. So I've pulled up the test data CSV to give the context. You'll see here the past index of zero, one, two and then the coffee id, the coffee name, the coffee type and its rating. So when I look at the coffee test service test, you notice here I've got parameterized test. I've told it I want you to take the CSV file located here and you notice the parameters that I've passed in, right? So you got 12345. When I look at the test CSV 12345. So again you want those to match up or it will throw an error message to you saying hey, you've got a couple of things in the CSV but not the same thing in the method name. What are you doing? So you can see here where I actually walk through and I parse the id that I passed in. I tell it okay go find by this and then return an optional of the mocked coffees that I created up here at the top that match that id giving that information and giving that viewpoint, right? So then I say okay, go get the coffee id when I do my asserts, right? Okay here's the pulled single coffee id and here's the expected name and migrating and the equality on it, right. So now what you're going to see instead of nine tests you should see eleven tests when we run this because of the fact of I have three items, right. Previously I was testing for just the one so I've added two more. So ten on eleven. So if I run the whole data set here. Okay, no thanks. Thank you intel or sorry vs code but I don't really care to do that right now. All right, so we will run all the tests here again prove no magic. Probably helps if I use those maven w clean test and you can see here I had eleven tests run. It's not going to show there. Not taking it there. My bad. But you can see the test run were eleven instead of nine this code time because we added two more tests by being able to use the parameterized test. All right, that concludes those. So here are the resources I use to pull this talk together again, I don't claim to be an expert and I always try to do my best to give credit where credit is due. In keeping with that those I want to give a special thanks to my teammates on the tax commons at the Home Depot. They were instrumental special shout. But to Jeff Anderson who gave a lot of feedback on this talk, helped make this talk better, as well as Jonathan Davis who helped me with Obs and getting this all pulled together. Lastly, and not least, I wanted to give a shout out to dinner bursary. He was my mentor when I first started into Java, told me about the conference I did my first presentation at this year at Devnexus. Without him I would definitely not be doing this today. So a huge thank you to him. All right, I've reached the end. Give me a second here and I will actually pull together my twitter handle as well as where you can find the code behind all this awesome work. So that way you can take a look see. All right, let me pull up visual studio code and I'm going to put it on a try to put it on a blank area. All right, so Twitter could like to find me. I am ehawk 61 on whoops, provided I can type ehawk 61 on Twitter. As far as the GitHub repo, if you go to GitHub.com 61, you'll find me. And actually I'm going to see if I can follow the link real quick because that's going to be faster than me trying to remember it. When you get to the page. See my face here and what you're looking for in those repos is migrating junit 405 and I will actually pull that together. Go back here into visual studio code and give the full link. Well, provided I actually copy and paste. Try that again. All right, so GitHub.com ehoc 61 migrating four junit five so you can find the code for all this. I'm in the process of pulling together slides to put up with the code that are exact duplicates of what I presented today. Feel free to reach out if you have any questions, concerns. Thanks again for the opportunity to speak today. Be safe out there and looking forward to when we're all able to be back together and in person. See ya.
...

Jonathan Meek

Software Developer @ The Home Depot

Jonathan Meek's LinkedIn account Jonathan Meek's twitter account



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways