Conf42 Enterprise Software 2021 - Online

BDD with JUnit 5 and Cucumber

Video size:

Abstract

This presentation will demonstrate the principles, practice, and benefits of Behavior Driven Development (BDD). We’ll show how to develop software that addresses the business needs and that follows the behavior of the end user: not only doing the things right, but also doing the right thing.

Summary

  • Catalin Tudose: Developing Java applications with cucumber. You are going to find out how to use cucumber, a behavior driven development framework. This talk is also related to automated testing in Java.
  • behavior driven development is a developing technique that is based on BDD. It is a methodology of developing it solutions that directly satisfy business requirements. In this demonstration, we will show how the application looks like using junit five and cucumber.
  • When is the keyword here and some consequences are expected. It is time to introduce cucumber as behavior driven development framework. This is the first cucumber project that we introduce.
  • Gerkin is the language used by the cucumber framework in order to describe the features and the scenarios. All these scenarios and the features are written here in a specialized file called a feature file. In order to execute such a test, I needed to add this cucumber test.
  • The cucumber plugin for intellij allows you to directly execute feature files. You can immediately get feedback about the scenarios and steps to be executed. Can you write more complicated tests? Can we write some tests that need some input for their methods?
  • The company follows a bonus policy depending on the passenger type and on the mileage. The scenarios for these parameterized features are known in cucumber as scenario outlines. These scenarios were transposed into methods. There is one to one correspondence between the columns and the parameters from here.
  • The demonstration introduced the BDD concept and the core cucumber facilities. Of course, there are more features and more capabilities of cucumber that are waiting to be discovered. See you in the next presentation.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
Hello everybody, I am Catalin Tudose. Welcome to my talk. First, a few things about myself. I am currently acting as a Java and web technologies expert at Luxo Mania and I am also an author at Pluralsight and Manning. I have recently published the Junit in Action third edition book. This talk is also related to automated testing in Java. The name of this talk is developing Java applications with cucumber. You are going to find out how to use cucumber, a behavior driven development framework, in order to make your applications better respond to the business needs. Otherwise said, you are going to address the needs of the users and you are going to do the right thing. First, probably you are accustomed with working TDD or test driven development. TDD is a well known technique. It has been introduced many years ago and it starts with a simple idea. First you are writing a test in order to verify some feature and as the feature is not yet implemented you are expecting this test to fail. Then you are writing the code to address that test. You would like to write the shortest piece of code in order to make that test pass. So first you write the test, then you write the code. You are driven by the test and after that you make the test pass. Eventually you refactor the code so you improve its internal structure while keeping its external behavior. And this is a simple but efficient technique and it has been applied for many years. However, it comes with some shortcomings. First, tests are tightly coupled to the implementation, so you have to understand and know some details of the implementation in order to write good tests. Tests are focused on the method or class that they are testing and you have to have a good knowledge about what they are doing. We can say that you are doing the things right, following things test driven development, you make sure that your code is working fine, but at the same time the business goals are neglected. In most cases, you don't follow the business needs and you don't have a good understanding of how the application must react to the user's input and to the user's need. We come to the next step, behavior driven development, which is a developing technique that is based on BDD. It is a methodology of developing it solutions that directly satisfy business requirements. So you have the business requirements in mind and you would like to directly satisfy them. You would like to address what the user needs. You keep on adding business value to the application and this is your main focus. Behavior driven development is a developing technique that also facilitates the communication between the business analyst and the developer. So you have a vehicle that will facilitate the communication and the interaction between these key people inside the project. And if TDD is making sure that you are doing the things right, BDD is making sure that you are doing the right thing, meaning that you directly satisfy the user's needs. Our vehicle for this demonstration will be a flight management application. We are presenting a company that is serving passengers and is providing flights for these passengers. And this company is following a few policies in order to allow passengers to apply for their flights. We have two types of flights, economy and business. And we have two types of passengers, regular passengers and vip passengers. And the company has defined its own policy for adding and for removing passengers to the flight. We are going to present some scenario here about adding the passenger to a flight. We say here that if the flight is economy, we are going to approve the request so everyone can join the economy flight. Otherwise, if it is not an economy flight and this means it is a business flight, then we have to look at the fact that the passenger is a vip or not and we can allow the passenger to join a flight only if it is a vip. If the flight is business, otherwise we are going to reject the request. So if we have a regular passenger, he or she cannot join the business flight and this is part of our business logic. Of course, the company is maintaining some policy for removing a passenger from a flight and I am going to show how this looks like in the code. We are starting to introduce this idea of behavior driven development by showing how the application looks like and showing how some junit five tests are running. I will start by running these junit five tests and introduce cucumber a little later. Just to understand how you make the step between using a general framework like Junit five and using a specialized BDD framework like cucumber, let's have a quick look together at these classes. We have this abstract class flight which is defined by the id and by the list of the passengers. It is extended by the business flight. And here we have the policies to BDD and to remove a passenger. As we are presenting. We can add a passenger to a business flight only if the passenger is a vip. Otherwise, we are going to reject that request and we cannot remove that passenger from the business flight once he or she has been added. For the economy flight, we also have some policies both for adding passenger and removing passenger. If you want to add a passenger, okay, he or she is accepted. If we want to remove the passenger from the flight, we can remove it only if he is not a vip. If he's a vip, we are returning false. Meaning that if the passenger has been added to an economy flight and he or she is a vip, we cannot remove him or her any longer. And the passenger is defined by the name and by the facts if he or she is a vip. Let's have a look at what we are using in our project here. We're saying that first we are trying to use only junit five. Pure junit five. And here I have added the dependencies for junit five. Junit Jupyter is one of the components of Junit five. In fact, it is the API for writing tests. And this is the test that I have written here in order to demonstrate how the policy for adding and for removing a passenger to a business flight or to an economy flight works. And I have already used the facilities of junit five. And I have written some nested tests in order to group how they are working together. You see here that we are having some economy flight and Mike and James are passengers and they belong to this nested class. That is economy flight test. It belongs to a larger class here. Airport test. It means here that when we are executing this airport test, we are going to execute the nested tests. We see here that we have airport test, having nested test, economy flight test and another nested test, business flight test. And here I also have a nested class regular passenger inside economy flight test. I can say here that we have two levels of nesting. Airport test contains economy flight test, while economy flight test contains regular passenger. And here vip passenger. So I use here the facilities of junit five, including here the display name annotation that will make the execution of the test easier to follow. For each test, we have here a setup. Economy flight, which is the flight and the two passengers also for other tests, have here other setup. Let's have a closer look at what the tests are doing before each we are initializing the flight and the two passengers. For the regular passenger, we check everything here that is working correctly. The id of the flight, the fact that the passenger has been added, the size of the passenger set, the fact that Mike is among the passengers. When we try to remove Mike, which by the way is a regular passenger, we succeed here. And after removing the mic passenger, the size of the passenger set is zero. What I use here is assert all method. Together with this assert equals. What's the benefit of using this assert all method that has been introduced by junit five? If I was writing only assert equals after assert equals after assert equals, then if some execution was failing, let's say here at the third, assert these assertions were not checked any longer with this approach. If I write here assert all, then I make sure that all assertions are verified. Even if we fail here at assert equals number three, the next assertions will be executed and I have here more testing. What I have made sure is that I used the junit five facilities, the display name, and we are going to see together how they look like and which is the benefit for using them in practice. And this assert all method that is using multiple asserts here. Let's run this test just like any other usual junit test. Okay, what's the big benefit here of using Junit five and the facility of display name? You see that it is possible to read these nested tests just like natural language and we can read here together. Given there is a premium flight, when we have a vip passenger, then you can add and remove him from a premium flight. Given there is a premium flight, when we have a vip passenger, then you cannot add him to a premium flight more than once. And you can keep on reading here also here you can read given there is an economy flight, when we have a vip passenger, then you can add him but cannot remove him from an economy flight. This is how BDD looks like BDD starts with a concept of given when. Then these are the keywords that are used in the BDD approach. Given something, we have a starting condition. When we do some action then we are expecting some results. And here you may have a first taste of how BDD acts because junit five is providing these nice facilities of nested tests and of display name so that you can follow easily how this execution looks like. Let's have here how such a passenger policy may look like in terms of BDD keywords. We implement here a feature called passengers policy and we say that the company follows a policy of adding and removing passengers depending on the passenger type and on the flight type. For each feature I can implement one or more scenarios. And the scenario from here is the scenario with economy flight regular passenger. If I follow the given when, then keywords, I can read it in plain English. This scenario given there is an economy flight when we have a regular passenger, then you can add and remove him from an economy flight. You cannot add a regular passenger to an economy flight more than once. So we have a given condition when represents some action we are pushing on something on the side of the application that is constructed and some consequences are expected. Then something else. Things is some core concept of behavior driven development. You have some precondition, something that is given you do some action. When is the keyword here and some consequences are expected. Then coming back here to the code, I run again this airport test just to emphasize these ideas of behavior driven development. And I see here again that I can read all the scenarios in plain English with the given when and then keywords given. There is an economy flight. When we have a vip passenger, then you can add him but cannot remove him from an economy flight. Things is fine, but we can do better. It is time to introduce cucumber as behavior driven development framework. This is the first cucumber project that we introduce. Now just to emphasize that the structure of the classes here is absolutely the same as previously presented, but we move our attention on something else on the test. I have just presented the way how a feature is written and how a scenario is written. And what I used there was the Gerkin syntax. What is Gerkin? Gerkin is the language that is used by the cucumber framework in order to describe the features and the scenarios. And all these scenarios and the features are written here in a specialized file called a feature file. Everyone can read it in plain English. Junit the way we were previously doing I can immediately read it just the way I was doing a little earlier. What's particular about cucumber and what do I need in order to start using it? First I look here in the palm XML dependencies and I see here that business the previously introduced junit five dependencies. I introduced these cucumber dependencies. They will be needed in order to execute the tests first, to annotate the method and to execute them. Okay, this is a feature file. I can read it in plain English, but how can I transpose it in code? If I have a look here, there is a passenger policy test that is already written. Let's have a closer look at how it looks like. And you see here that there are plenty of methods that are annotated with given when. Then this is something new. These are some new annotations. Where do they come from? If I look here at the import, of course they are coming from the cucumber packages. And if I have a look here, given there is an economy flight and if I have a look here into the feature file, I see that there is a correspondence between this step from the scenario end of this feature file to this step here. So whenever we'll execute this step from the scenario, in fact things method will be executed. Then if I have a look here, when we have a regular passenger, there is a corresponding step here. The method annotated with the when annotation and we have a regular passenger and this is what is going to be executed at this step. Then you can add and remove him from an economy flight. Then you can add and remove him from an economy flight. It is the corresponding step from here. This end step here is in fact another consequence, another then and it has been annotated here. The method with this then annotation as well and what was previously written with nested test and using only junit five facilities. It is written here using cucumber and the cucumber annotation. The cucumber annotations we see here that there are no more nested tests. Let's have a look back to our previously demonstrated junit five tests. We see here that we are having airport test having economy flight test included nested and economy flight test has regular passenger and vip passenger as nested tests. While here we are having a linear structure. All methods, all test methods are at the same level. How can I execute such a test? In order to do this, I needed to add this cucumber test. This is a special file. It may have any name. Just I chose cucumber test for convenience and what I need to say here, I need to run this test with the cucumber runner and I provided here some cucumber options. Pretty will mean the way the tests will be displayed. We are going to see this really quickly and where to look for the feature files and we say here look on the class pass and you are going to find out this features folder more exactly this one. And there you are going to find the feature file or the feature files and you are going to make some correspondence between the steps that are defined here and the steps that are defined in the Java code. Okay, let me run this youtuber test. Okay. What I see here is that I still have some scenarios, but it is easier to read them of course in plain English. Just the way we are doing previously with junit five and the junit five capabilities. Given there is an economy flight, when we have a regular passenger, then you can add and remove him from an economy flight and you cannot add a regular passenger to an economy flight more than once. Let's compare this with the previously executed test from junit five. You see that they are looking pretty similar, but the cucumber ones are easier to read. You don't have to go into some depth. They are linear here and you can eventually immediately read the whole scenarios here into the feature file. If we want to do some more comparison, let's look at the length of the code here for the cucumber version, the code written for the test is about 157 lines, while here it is 207 lines. So we also have some gain here. At the level of the code we have a shorter code and the shorter code is easier to understand, to follow, to maintain. Just because cucumber as any behavior driven development framework in general, is providing us some facilities to write linear test and to write each step that is repeated to define only once a method for it. What I do mean here is here, if I have the given there is an economy flight step and I have again given there is economy flight step, there will be only one method annotated with given there is an economy flight here. So you have a shortage of code. And of course things comes as an advantage. What do I need in order to easily use cucumber in my projects? I was saying of course first of all, remember I need to add these dependencies. Great. What else, what else is needed or at least recommended working with the cucumber plugin for intellij here brings to some facilities. I'm going to demonstrate them immediately. Just to say here that I needed to add the cucumber for Java plugin and the Gerkin plugin. Remember I was saying earlier that Gerkin is the language that defines the scenarios that cucumber needs to use. Cucumber is the framework while Gerkin is the definition language. Let's see what this plugin can help me to do if I want to execute directly these scenarios. This feature with these scenarios, would that be possible? If I right click on this feature file, let me execute it. It is possible as you saw that Intellij was providing a run button, I can directly execute it and I can see here I have six scenarios 22:06 steps, 22 past great. What did I need to do in order to be able to directly execute this feature file? One thing was to have this cucumber plugin installed. Then I need here to have some cucumber Java configuration that needs this main class as executor cucumber API Cli main glue is the BDD airport meaning the package where I wrote the code. You see here I have BDD airport as the package where the code is written and the feature or folder path is where the feature file or feature files are to be located. After this pretty simple setup, as you are seeing, I am able to directly execute this feature file. And remember this is very nice feature, especially for nontechnical people or even for technical people if they are maybe in a hurry, you will immediately get feedback about the scenarios and steps to be executed and about their results. Okay, let's have a closer look at the step from this feature file to this Java file. And you may ask yourself, how can I do such a thing? Quickly, how can I write this method and how can I quickly take the annotation, the annotation that is needed for such a step. You see here we have this given there is an economy flight and it has added, cucumber has added this given and this argument there is an economy flight. Let's have a look. Let's presume that this step is missing here from the implementation. If I have a look here at the feature file, the plugin will immediately detect that, oh, this step is missing and it will highlight it with another color. And if I try to execute now this feature file, just the way I was doing a little earlier, let's see how it goes. Okay, it fails, not a surprise for us, says here undefined step given there is an economy flight, and if I have a look here, I am provided an advice. You can implement missing steps with the snippets below and it immediately gives me this given there is an economy flight annotated method and I can just copy, let's presume that I didn't have it and paste it here. It was similar to this already implemented method and I can just write the Java code that corresponds to that action. So you can immediately obtain the skeleton of the test by executing directly this feature file and by taking the not yet implemented steps from here. Just to tell you that there is no semantic difference between these steps given when, then these annotations do not have a semantic difference between them, they just correspond to the steps from here. And of course they have some understanding significance, because if you write given and you read given, you understand that this is a precondition. If you write or read, when you understand that this is an action, and if you write or read, then you understand that this is a consequence. Let's move forward and let's try to implement some more functionality. You may ask yourself, can we write more complicated tests? Can we write some tests that need some input for their methods? Can we write some parameterized tests? Yes, this is possible. And in order to demonstrate this, we take this feature about providing bonus points to the passengers. We say that the company has a bonus points policy saying we would like to calculate the bonus points. What do we need to do? We take a look. If the passenger is a vip, we take the mileage and divide this mileage by ten and we are getting the bonus points. Otherwise, if the passenger is not vip, we are taking this mileage and we are dividing it with 20 and this is the bonus points. So let's have a look at the implementation of this new feature. It is a parameterized feature. The scenarios for these parameterized features are known in cucumber as scenario outlines. So we have this separate feature saying bonus policy. The company follows a bonus policy depending on the passenger type and on the mileage. I can immediately read here scenario outline regular passenger bonus policy given we have a regular passenger with a mileage when the regular passenger travels mileage one and mileage two and mileage three, then the bonus points of the regular passengers should be points. You see that we have some parameterized steps and at the bottom of this scenario outline we have a table with examples and for this table with examples we have mileage one, mileage two, mileage three and points. And you may immediately understand that there will be a one to one correspondence between the values from this column, mileage one that will be introduced here, the values from this column that will be inserted here, the values from these columns to be inserted here to mileage three and the values from this points column to be inserted here. So we have four columns corresponding to these four parameters and we have five lines meaning that things scenario outline will be executed five times for each set of values. And you see here two scenario outlines the scenario outline for the regular passenger bonus policy and the scenario outline for the vip passenger bonus policy. Of course the same example stable with one to one correspondence between the columns and the parameters from here. These scenarios were transposed here into these methods. You see again this one to one correspondence between this annotated method given annotated method and this step from here and for example between this when annotated method and this when step from here and what you need to see to observe in addition is that these three parameters from here have been translated into these three regular expressions from here and into these three parameters of the method. So when the cucumber plugin generated this step, it has generated this when annotated method and a method with three parameters, mileage one, mileage two and mileage three, each one corresponding to one of the regular expression d plus here means some integral value. Again this step from here, then the bonus points of the regular passenger should be points has one parameter. It has been translated into this then annotated method and this regular expression from the argument and the method with one argument here int points just to have a look here that a new mileage class was introduced in order to make the calculus for the given points, for the points to be awarded to the passenger according to the mileage. This is pure business logic here. And following the same strategy, when you write this test, first you think, what do I need in order to provide the business logic for this given step, which are the preconditions? What do we mean that we have a regular passenger with some mileage? What does it mean that the regular passenger travels some mileages? What does it mean that the bonus points of the regular passenger should be something? And this cucumber test is the same one. This cucumber test is the same one. I can right click on it and execute it. Let's wait a little here we are interested about this bonus policy new feature. We see here scenario outline with examples. And we have the five lines of examples that were present into the feature. The same here we have here five lines with examples. This means that the test is executed once for each line and it checks accordingly for each input stat. Let's try to execute things bonus policy feature directly, just the way I was doing previously with the passenger policy feature. And we see that we get immediate feedback. We may read here ten scenarios. Remember we are having two scenarios outlines, each one having five examples. So two multiplied by five means, ten scenarios and 30 steps. Let's have a look here at how the methods are generated and presume that this when method is not present here. You see here that the cucumber plugin will immediately emphasize that the method is not implemented. Says undefined step reference. And if I run again this bonus policy feature, okay, it is failing. But if I have a look here, I am told, hey, you are missing this step. And the cucumber plugin is providing immediately the when annotated method with these regular expressions and the method with three arguments. So let's go back here to bonus policy reintroduce things method. Have a new look here. Okay. The plugin has found out that the method is back and if I want to re execute this chuchumber test, I'm expecting everything to be working and green again. Okay. And this is what is happening. So we are getting closer to our end of the demonstration. I hope you have enjoyed this cucumber facilities and that you are going to find out that it is useful for your projects and you are going to adopt this BDD style. Of course, there are more features and more capabilities of cucumber that are waiting to be discovered. Our demonstration introduced the BDD concept and the core cucumber facilities thanks for watching. See you in the next presentation.
...

Catalin Tudose

Java & Web Technologies Expert @ Luxoft

Catalin Tudose's LinkedIn account Catalin Tudose's twitter account



Join the community!

Learn for free, join the best tech learning community for a price of a pumpkin latte.

Annual
Monthly
Newsletter
$ 0 /mo

Event notifications, weekly newsletter

Delayed access to all content

Immediate access to Keynotes & Panels

Community
$ 8.34 /mo

Immediate access to all content

Courses, quizes & certificates

Community chats

Join the community (7 day free trial)