 Hello everyone, my name is Karl-Hans Moves. I'm trying to tell you something about JNU and Jupyter platform unit testing. I'm doing very basic stuff based on the time because we are really limited. Well, we'd like to make a real talk about that. We could take two, three, four hours or more, even more. Just about something about me. I'm working as a German book freelancer, working with driver and all that fancy stuff. I'm always also a part of the Apache Maven PMC. I'm a Apache Software Foundation member, as you're already heard by Christian. So we are working a little bit together on some parts of that. What I would like to do is show you some code. I don't want to make much slides here. I just wanted to show you some code. Start that way. So I'm sitting down then. That's the reason why I'm sitting in here in front of the keyboard that you can see what I'm trying to do and show your real code. So where we begin is a very simple, simple class. Don't blame me about the code quality or something like that. That is simply just a class to show some identities or how to do some unit testing. I think you can implement that better than I do, but it's just a kind of a presentation for a code. So we have a simple static members here, a very simple thing. And we think about things like JUnit4 to write our unit tests. And I would like to show you some differences between JUnit4, for example, and maybe some information about test and G in comparison to JUnit5 platform, for example. So let us start with a very simple use case and write some unit tests here in a simple way based on JUnit4. You see some examples here. We will start with this one here. Very simple things. We wrote a simple test class, of course. We have to make it public, things like that. We have to name somehow the methods, of course. We need to write down the code. What I'm using here for assertion is not the basic, which is provided by JUnit5 platform. I'm using here the SSAJ library, but we'll come to these details that come in later a little bit. Then you see some test code here, of course, and just writing some test methods here. All of them, of course, annotated with the test annotation, like the usual case here is done in JUnit4. What you see is that I have implemented with some intention that I have a method which is called require greater than zero, where I have two implementations of, one for integers, one for longs. Okay, you can do that different, I know, but that was intentional here somehow. So you see the different things here, and one thing I have to do here in JUnit4 is to name the methods different and make them have a different name because otherwise they clash simply. I'm really doing technically the same. You can see that very easily if I do that that way here. Then you see one with a prefix in for the integer part and one without for the long part, of course. So if you really do that in JUnit4, it comes a little bit clumsy over the time if you write some kind of that test. That's a little bit weird. Why do you need that? You can, of course, rename the methods in another way or whatever, but in the end doesn't help because you're naming the methods based on an intention that they are overloaded the parameters, of course. So it might be not the best case here. So let's go to how to use that or how can you write that in JUnit5 platform, for example. I started here with a little bit parts here. Just make a before all and a before I will come later to that. Just print out some information. It's not very useful at the moment, of course. I hope you will not blame me for that. It's just to show what is possible here. So the first part is to do that simple and translate to the JUnit5 platform and there are some capabilities which are also supported by JUnit5 that are remarkable in this case. What you see here is the difference that all the public modifies had been removed. It is only necessary to have a class in a package default or package private. I don't know what you prefer in that case. So I can remove the public from the class. I can remove the public from the methods as well. But in the end, the only change here in the end is to remove that and add the annotation of the JUnit platform, of course. That works perfectly. But at the end here, you are coming to the point, as I said, you have duplicated methods name and things like that that looks a little bit strange. So there must be a solution for that to do that in a better way, of course. And of course, nicely, the JUnit5 platform supports exactly that. That you can do that and handle that in a correct way. It's much more easier to handle and to get better understanding tests. Let us take a look. What you can do is introduce so-called nested classes. That means you can make a separate class in your test class. You have to mark it with the nested annotation and then you can name the class however you like. And indirectly, then you have a kind of categorization or a naming schema and drill that down for your classes. And what you have, and if you take a look on the structure of that, then you see something like that. Then you have a real test class on the first level, on the root level, which is named here can precondition to class. And on the second level, you have required then zero long. Maybe I should think about my naming. That could be better, of course. And another one required then zero for integers, of course. So now you have solved the problem that you need to rename the method names. I can exactly name them exactly the same. And I have exactly a reference between the different classes for integers, for longs, and so on. That's one of the nice things. I can also run them, of course, from your IDE, of course, as usual, that works for IntelliJ, that works for Eclipse, for NetBeans, and all that stuff as well. So as you see, you have a construction here, is created in a tree based on the things you are executing. Which is also possible that I say, okay, I wanted to run only the test for the int or for the longs, just doing that as an example here, just running them here. I can limit that. Of course, you can run a single test. Of course, that's not a problem. But you see they have a categorization and a grouping of your tests. Which is very good to have such easy separations of different tests. That makes it more, more easier. Let us take a look. And one of the things is coming up, as I said, based on the naming what you have, is that you name your classes in a good way. What you can do is, of course, if I would like to, let me take a look here. You say, okay, require them. Dero is not a very good descriptive name. You can, of course, rename the classes with your ID. It's not a problem. Then you come to the point, you would like to make it more descriptive. Not a name in a class somehow described what you are trying to express in your tests. And then there is a coming in interesting thing, which has been introduced to JUnit5 platform, is so-called display name. That means you can give a description for what is shown on the output. So you can do that on the root class, of course, and give a different name what you like. I just have used here very short things. You can write, of course, a poem if you like. Might be not that useful, but it's possible. And then you can do that also on the different nested classes as well, make a categorization. And it's also possible to do that on the test method. So what you will get then in the end is something like that. You can get a complete different look on your test structure here. If you do that with a precondition and thinking a little bit about that, then you can construct here very good sentences. If you do that in the correct way, just playing around with that, then you can construct here real sentences and describe what you are doing here. For example, if you read that, that works very good here. That's not perfect, of course, just to show you the direction where you can go. If you do that more and more often, the more familiar that becomes, and it's more easier to understand what you're exactly doing. So you can read here precondition four integers require greater than the error should return the same object, for example. And then you can do something like that. That's an easy way to make your tests create more a story. Sometimes you call that maybe behavior-driven development, which you can do a little bit in that direction. It's of course not a behavior-driven development framework, but it can help to get into this direction and make it more descriptive, of course. Sometimes you have the problem if you want to have different names based on the class names or on the method names, of course. It is possible to define a display generator. You can use the built-in ones or you can write completely your own. Then you can say if I separate the methods, for example, as I did here and separate with an underscore or something, then these classes or results will be printed out without the underscores and I see more or less exactly that sentence of this. That's also possible. There are some that are predefined. You can implement it however you like. What is also possible in some tests is sometimes necessary to make a condition to run that test, for example, on different platforms, for example. I don't want to run this test here on a macOS, for example, or on a Linux or on a Windows box or something like that. That's very easy to express with JUnit5 platform. Then you can say I just wanted to disable this on macOS. That means it will not run on macOS, but it will run on all other platforms. It's very easy to express. There are several others. I just wanted to know, given you mentioned them. I have done that on here. You can disable on a particular JDK. The start is JDK8 because JUnit platform itself starts with JDK8, so below will not work, of course. What you can do also is to enable that. Exactly the opposite. You can enable the tests like this. So I would like to run this test only on JDK8 or just run them on Linux. What you can also very easily create is so a meta annotation that can be combined and make your tests more readable. I can combine that for my own. So I have created a very simple annotation here just for demonstration purposes, where I say test on Linux. That's nothing else than the combination of the test and enabled on operation system annotation. But it's very easy. You can do much more complex things if you like, but we're scratching here only the surface, of course. Things like before and things like that, as you've seen in the JUnit 4 part, you can do that, of course, as well. So it's not a problem to define them all. They have been named a little bit different. I think it's more clear now, before all means really before all tests. Before each means really before each test. And after each and so on, that you can do. What you can combine, of course, is I have defined them here on the level of the surrounding class. And now I can do that on the nested classes as well. So I can combine that with disabled and things like that. So I can completely make it very easy to make different configurations. What is also possible to make an order, execution by order. There are some in JUnit 4 where you can define by the method order, alphabetic, things like that. In JUnit 5 platform, you have the opportunity to define the order by an order annotation or alphabetic sorting and things like that. Then you can define the order by yourself and combine them, of course. Just to... It's randomly connected to the end force. Yeah. Or you can define, of course, if you would like to have a random order all the time, you can define that on your own, if you like. Then this makes sure that everyone is running a different order of your tests. That keeps your state from that. What is also possible to do some parameterized tests, it's a little bit tricky or it's more different thing. You can define a method, your test method, given an argument, and define a so-called method sort. If it's not defined, it will automatically get the name as the name of the test method. You can define it explicitly, give a stream of arguments, which is put into the argument list and run them all that. And it's easy to understand that because if you do that, then you see all the solution of the arguments is also displayed. You can run and it will jump to the right correct level. You can run that simple test with exactly that parameter set. That's extremely helpful in particular. Let us take a look into parameterized test. Yes. Yeah, I know. It's very limited, I know. I've done that very, very small calculator test. You can do things like CSV sources. You can define a parameterized test where you need to add a supplemental dependency, which is called JUnitUptrParam, if I correctly remember. Then you can define the string which is used to format your output of how it looks like in the output for the display, like this. So you see what I've defined here. If I would like to do that in a more different way like this, then I can do that as well. If I would like to rerun that, then you see, of course, I can change that text. You have some placeholders here which exactly represent the parameters of your test and so on, and then you can create that and make that very descriptive. What you can do which is very interesting is you can test interfaces. An interface since Java 8 can contain code, a default method, something like that, and I've written a very useless function, of course, just a default method, but you can test that very easily. You can just say on the test, just implement that interface and I can just run that test and call that method. So you can call that very easily and you can call static methods or default methods on an interface. It's very easy. Dynamic tests, I will go only to the surface here because it's very complex. Usually you write your test, implement that during the build time. You describe what you are exacting going through the steps. But with dynamic tests, it's possible to define what is really tested at runtime. So you can think about that. I have a large number of classes that have a marker interface. I would like to write some special tests, for example, an equals method, something, as an example, but I don't want to write 500 tests by hand or something. Okay, parameterized would work, but it's limited. So you can make that dynamic and run and create the test dynamically. Completely. That means it is possible to write, not to write the test itself. You can write what the test here is and that will describe what the test does. It is in the end not limited. You can make a lambda function or completely call a method or whatever is possible. So you can do, to be honest, really fancy stuff. And it's very interesting to have power in that. What is also interesting to have are called an extension. Everything in JUnit Jupiter is based on extension, more or less. Of their own, they were using their own. That the extendable of JUnit4 test and G is very limited. There are some rules like that or something like that. You can, there's a limited to before and after or something like that. But in JUnit5, you have the opportunity to really do that in a very interesting stuff. I just skipped some code here. You have so many extension points that is possible to extend your, make right extensions to support you. And I have made a very simple one here, just a very simple one here. Which is something like, I would like to have a so-called a timing extension. I simply stole in that from the documentation, which is very simple example. I would like to see how long my tests are running. Just a very simple thing. You can do that with defining that here with extend with something like that. Then you implement that class, that, sorry. That's of course not right. Go into that and this is the whole extension. What you do is you have an interface which you're calling, implement the extension point and you can do what you want. There's internally a hash map which is supporting you to store parameters which it can be holding between different steps of your things. And then you can implement such things that makes it very easy to implement things, what you like to do. And just see that here. Just click on that. Then you see took 62 milliseconds or something. You can imagine I've written things like with an end-to-end test and something like that. And that can be combined into your own annotation. It's very easy to do that. And then you can combine that and make your own annotation and write that and use that which combines these different things here and makes it much more easier. And then you can simply replace your extend with here with timing, yeah, time. I need to write it the correct way so I can do that and I have run that, I can do that. It's a very easy thing. I've written in the meantime several extensions which it makes it very easy to do stuff which is with JUnit 4, TestNG, very complex and very hard to handle. Yeah, I know, exactly. Just wanted to show a simple example which is a little bit bigger. I've written an extension for Maven, of course I'm working as a Maven developer and I would like to make my experience about integration tests better. And that was a hard part. And I've written JUnit Jupyter extension to handle that and all the stuff which is in there and I can express the test in my IDE and run them and run stuff behind, in the behind, I can start my Maven and make a local cache and all that stuff is possible and that makes it possible to handle things like that or Spring Boot Max does the same way. There is an extension. If you write Spring Boot Test with JUnit Jupyter, it's nothing else than an extension. It's an extent with if you take a look into the annotation. So based on the time, that's it. I have some links here, I will put it online. I can give you only a rough overview of the possibilities. We are not limited to that. I have just ignored many, many, many details because there are so many things. I hope you have some time to look at and I can strongly recommend to do that because it makes testing really easier. Thanks. If some question, maybe obviously a minute or two for some questions. Can you give me the title which is shown in the... Yes, you can use the display name, for example. If you like. And the parameter test has also an annotation where you can write a description, yeah? And there you can access the parameters. Yeah, exactly. Yeah, exactly. That's possible, yeah? That's the parameterized things with lambda and... That's possible, too, yes? Yes, but when you do a two string on the lambda... Yeah, not from there. Then we have to give it back to you and make it my set for a long time. Yeah, but... Currently, you have two forms of lambda. You have to serialize lambda. And for serialize lambda, you have more information, but JUnit doesn't... Yeah, correct. Pull request? Yeah, pull request. Okay, is IntelliJ smart enough to help you with the display names when you refactor names of functions? No, it does not. No. Why would you... I'm sorry? So why would you use them? You're stuck with remembering that you need to change these names. Because it describes more the intention of my test. Is that what you... The problem is you can't write spaces or something like that. It's limited based on the naming schema of Java, of course. And sometimes you would like to write more information or just write a sentence with a comma or something like that. That's not possible in a method name. And it helps a lot to describe, of course, we can just... It's a matter of personal taste, of course. Yes, fine. If you run that with the vintage engine, they will run, but they're running not with JUnit Jupiter. They run real with JUnit4 and other hoods. Yeah, you can use before, things like that. But that will... Yeah, you have different befores, all before each, things like that. And that's a reference counting. Yeah, reference counting, things like that. If you need to really do that, I would take a look what exactly kind of rules you're using. Most of the time I've used with exception, things like that that's not necessary anymore or test containers. There is an extension as well. It's very easy to write your own extension if you really need it. The migration is very easy. Ah, okay. There's an annotation for it. You can do class-based or method-based. Method-based, yeah. So sweet would run with one color down. That would you do with an extra resource that you can manage whatever in extension. In extension, yeah, yeah, exactly. There was another one. If you use... I'm using Makita most of the time. And there is an extension as well you can use in relationship with JUnit5 that supports Makita. For example, in Springboard or something like that. Yeah. It's also an extension in JUnit, Jupiter. Yeah. Other questions? Okay.