Selecting dependencies

This blogpost was also published on Medium.

Open source software is everywhere. Most likely you are using some open source projects either at work and/or in your side projects.

Pros and cons of using dependencies

One of the upsides of using Java as a programming language, is that there are libraries and frameworks available to do many of the things we want to do in our projects, but don’t necessarily want to write ourselves. Using existing libraries and frameworks helps us deliver business value faster.

Unfortunately, there are also downsides to using external dependencies. The most dangerous being when security vulnerabilities are found in libraries many of us use, like the Log4Shell vulnerability in the log4j logging library that was disclosed in December 2021 and the Spring4Shell vulnerability in Spring in March 2022. These vulnerabilities were so severe that we had to patch all our services ASAP. Even if the version of a dependency you use does not have any known vulnerabilities, you might need to update them for other reasons.

In addition, adding dependencies to your project also has an impact on the size of your binary. For example, Brian Vermeer has created a demo to show the number of lines of code written versus number of lines pulled in by Spring. Granted, he admits that “this was the most useless Rest endpoint you could ever write”, but this demo clearly shows how the code pulled in by dependencies can overshadow to amount of code you write yourself.

A balancing act

This means we have to think carefully about which dependencies we want to use. Some developers try to add little or no external dependencies to their projects. This is one way to avoid the downsides mentioned above. Another argument may be that it gives you more control over the code in your project. Of course, the downside here is that you have to write everything yourself, which might not always be the best idea. For example, I’d rather use JUnit and Mockito than write my own testing and mocking frameworks.
On the other hand, we shouldn’t just add any library or framework, as we’ll have to not only implement them now, but also maintain them over time. Or even remove them in the future, which is not always easy. Some projects, like Lombok or Reactor, will be present throughout your code base and hard to remove should you ever want to (for example, when moving to Kotlin & coroutines).

Most of us will be somewhere in the middle; we don’t want to write everything ourselves, and we will use certain frameworks and libraries that offer us some useful functionality, but we also want to make sure we can continue to maintain our project without having to (urgently) update dependencies or rewrite our code because something is vulnerable or otherwise outdated.

What to consider when selecting dependencies for your project

The best time to check your dependencies is before you add them. The second-best time is now. So take a critical look at any dependencies you’re adding or already using and consider the following:

Do we really need this dependency?

To make it worth it to use a dependency, it has to solve our problem and do so without adding new problems. We need to consider if the project fits our needs. We can do so by reading the documentation, and by seeing what experience other users already have with a particular tool. Keep in mind that, just because other users are enthusiastic about a particular library, that doesn’t necessarily mean it’s right for you. Their context or use case might be different from your own. There might be other libraries out there offering similar functionality that are a better fit for your project.

Also consider how much of the library you’ll actually use. If it is only a small part, consider other solutions. For example, do we really need to import StringUtils to use it for one or several String functions, or can we write them ourselves? (And, if we moved to Kotlin since then, we might be able to replace them with standard Kotlin functionality.) Or are we already using another library for this particular problem? For example, we won’t need gson if we are already using jackson (or vice versa)?

Is the project well maintained?

If a project is no longer maintained, we run the risk of having to urgently replace it if security vulnerabilities are found. To see if a project is actively maintained, you can check when the last release was, and how frequently new versions come out; you can find this information for example on Maven repository. You can also check when the last commit was, and whether the project is maintained by one person, or a group of active maintainers. A project that depends on one particular person runs the risk of becoming unmaintained if that person no longer has the time and energy to maintain that project. Maintaining a successful open source project can be a thankless task and maintainer burnout is real. With multiple maintainers the load and risk can be shared. You might want to look into how many open Issues and Pull Requests (PR) there are, and the interaction on those Issues & PR’s. You can find this information on GitHub or wherever the code for the project is kept.

How popular is the project?

A popular project might have more stars, watches and forks on GitHub. Although these metrics don’t necessarily mean that people are using it; they might have starred it to try it out later. These metrics might be useful when comparing similar tools, but not necessarily when comparing different tools.

A widely used project will likely have more people talking and writing about it. Having a large number of users means more people who are able to help out others. It also means there are more potential contributors, but unfortunately a high number of users doesn’t always translate to a high(er) number of contributors. And just because a project is popular doesn’t mean it’s right for you.

What is the community like?

Consider whether the community is friendly and welcoming. How do they interact with their users and (potential) committers? How do they respond when issues are reported? Do they review PR’s quickly and offer constructive feedback? Friendly maintainers often make for a more friendly community.
They might be active in official support channels like Slack, Gitter or mailing lists, or help answer questions on StackOverflow, write talks and blog posts or find other ways to share their knowledge.

Is it easy to use?

Finally, consider whether the project easy to implement & use, and whether you like using it. Developers have personal preferences with regard to almost everything in software development, including which tools they like to use. If a popular framework doesn’t work for you, and you have options, choose something else!
Part of whether a project is easy to use might include how well documented a project is. Good documentation can help make it easier to use. Consider looking at the official documentation, as well as blogs and content created by users. The official documentation will (hopefully!) explain how a project is meant to be used.

What is the latest stable version? Are there any open vulnerabilities?

Once you’ve decided to import a dependency, make sure to add the latest stable version. We don’t want to add an older or unstable versions that we then have to update. And we definitely don’t want to import a dependency that has known vulnerabilities that have not (yet) been fixed! We want to keep our software secure and maintainable.

Where to find this information

As mentioned, there are several places where we can look for information about a dependency we are considering. One is Maven repository where we can find open source packages, their versions, whether there are any known vulnerabilities and more.

For example, when we look at Jackson Databind on Maven repository we see a list of versions and their release dates, we see the number of usages by other artifacts for each version, and we see a warning in red for versions with known vulnerabilities.

Jackson Databind on MvnRepository
Jackson Databind on MvnRepository

When we look at the details of a version with known vulnerabilities (Jackson Databind v2.13.2 in this example), we see the CVE number for this vulnerability which links to the details for this CVE). There is also a warning in yellow that there is a new version for this artifact with the link to that version.

Details for a vulnerable version of Jackson Databind
Details for a vulnerable version of Jackson Databind

Another is to find the project’s code on GitHub, to look at the code itself, see when the latest commit was, look at open Issues and PR’s, and check Insights for more details on contributors, frequency of commits and other activity.

Jackson Databind repository on GitHub
Jackson Databind repository on GitHub

We can look for official documentation and read (or at least scan) it to see whether the project is a good fit for us, and whether it is well documented.
Other information might take a bit more effort to find: Go into the support channels and ask questions. Search for blog posts (or YouTube videos, if you prefer) and other places where you can find information. We might even check StackOverflow to see whether there is a tag for this dependency, how many (open) questions there are, etc.

JetBrains has created a Package Search website that can be used to search for Java and Kotlin libraries and get a lot of this relevant information, including the latest (stable) version, links to relevant tags on StackOverflow, links to the official docs and the code, and if the project is on GitHub the number of stars, watchers and forks on the Information tab. A list of versions (similar to the one on Maven repository) can be found on the Versions tab.

Jackson Databind on JetBrains' Package Search
Jackson Databind on JetBrains’ Package Search

The Package Search plugin is even bundled in IntelliJ IDEA 2021.2+. So, if you are using IntelliJ IDEA, you can search straight from your IDE!

Conclusion

Carefully consider which dependencies to use, taking into account at least some of the things we have discussed here. The best time to do so is before you start using them. But don’t forget to periodically check the dependencies in your existing codebase to see if you still use them, and still want to use them based on the considerations above. Don’t be afraid to remove them if they no longer bring you value.

Presenting with IntelliJ IDEA

In this screencast we’re going to look at some ways to level up your presentation skills with IntelliJ IDEA.

Chapters:

00:00 – Intro
00:11 – Presentation Assistant plugin
00:57 – Presentation Mode
02:06 – Mouse Zoom
02:43 – Font
03:11 – Theme
03:48 – Tool windows
05:13 – Find Action & Soft-wrap
05:58 – Shortcuts & Navigation

Links:

• IDE viewing modes: https://jb.gg/erihcm
• IntelliJ IDEA keyboard shortcuts: https://jb.gg/z9pxdd
• IntelliJ IDEA reference card: https://jb.gg/2jyfzi
• Configure keyboard shortcuts: https://jb.gg/a81689
• Creating custom shortcuts: https://jb.gg/sn3pk1
• Source code navigation: https://jb.gg/4jpnu4
• Example code: https://jb.gg/zr7v7h

Using Git Interactive Rebase

This article was published on Foojay.io on August 25, 2022.

This tutorial will cover how to clean up your Git commit history with Git interactive rebase, both via the IntelliJ IDEA UI and from the command line.

Git interactive rebase allows you to change individual commits, squash commits together, drop commits or change the order of the commits.

This allows you to clean up your Git commit history to make it linear and meaningful, which can make it easier to understand the history of the project in the future.

Open the Git window in IntelliJ IDEA using ⌘+9 on Mac (or Alt+9 on Windows & Linux). In the Git log window we can see the commits that were made to the project.

We will use a Git demo project available on GitHub. This example uses TDD (Test Driven Development) to add a new feature.

In TDD, we start by adding a failing test, writing the minimum of code we need to get that test to pass and finally do some refactoring.

Even though we made the necessary changes in multiple commits, we don’t need to keep all these individual commits for future reference.

Using Git interactive rebase in the UI

We can use Git Interactive Rebase in IntelliJ IDEA as follows:

In the Git history, identify the commit from where you want to clean up your history. That will be the oldest commit in the series of commits you want to clean up; in this example, the first failing test that we added.

Right-click on the commit from where you want to clean up your history and select “Interactively Rebase from Here…“.

IntelliJ IDEA context menu with the option "Interactively Rebase from Here..." highlighted in blue

This will open the “Rebasing Commits” popup window with a list of the commits that were done on top of the selected commit.

IntelliJ IDEA "Rebase Commits" dialog

Notice there are several options at the top of this popup, that become active when we select one or more of the commits:

  • Reword allows us to change the commit message of a specific commit.
  • The Squash button is actually a dropdown that allows us to choose between Squash and Fixup. Both options will combine the changes made in the selected commits into one commit. If we select squash, by default the individual commit messages will be combined. If we select fixup, the commit message of the fixup commit will be discarded. You can select fixup while in the “Rebasing Commits” popup with ⌥+F on Mac (or Alt+F on Windows & Linux)
  • Drop allows us to drop one or more commits.

Changing the order of the commits

Let’s say we want to change the order of the commits; we want to keep the unrelated change, but separately from the changes for the new feature. We can select this commit and use the up and down buttons on the top left to change where in the order this commit will be.

List of commits in the "Rebase Commits" dialog window, with one commit selected.
List of commits in the "Rebase Commits" dialog window, with the  selected commit moved down.

Once we’re sure about the order, select “Start Rebasing“. We see in the Git log that the order of the commits has changed.

Combining multiple commits into one commit

Next, we want to combine multiple commits where we added the tests and implemented the new feature. Let’s reopen the “Rebasing Commits” window and select those commits.

List of commits in the "Rebase Commits" dialog window, with several commits in a row selected.

Now, because we want to combine those commits into one commit with one commit message we select “Fixup“, and then select “Start Rebasing“.

The Squash dropdown selected, with the Fixup option selected in the "Rebase Commits" dialog window.
List of selected commits in the "Rebase Commits" dialog window, shown in a tree structure ready for Fixup.

In the Git log, we can see that multiple individual commits are now combined into one commit with one commit message.

Drop a commit

Finally, we want to drop the commit with a mistake that we made. Let’s reopen the “Rebasing Commits” window, select the mistaken commit, select “Drop” and select “Start Rebasing“.

List of commits in the "Rebase Commits" dialog window, with one commits selected.
List of commits in the "Rebase Commits" dialog window, where the selected commit it shown with strike through.

We see in the Git log that the commit is dropped.

Rename a commit

Now that we have cleaned up our commit history, we might want to rename the commit where we added the new feature. We have several options to do so.

We can do so using Git interactive rebase, in the “Rebasing Commits” popup, by selecting the commit you want to rename and clicking the “Reword” button at the top of the popup. This will open a small editor pane where you can reword the commit message for this commit, apply the change to the message and select “Start Rebasing“.

Open dialog to Reword the commit message.

You can also edit the commit message directly in the Git log window. Right-click the commit you want to rename and select “Edit Commit Message” or press F2 on macOS, Windows or Linux.

IntelliJ IDEA context menu with option "Edit Commit Message" highlighted.

This will open a “Edit Commit Message” popup, where you can edit the commit message and click “Ok” (or “Cancel“) when you are done.

IntelliJ IDEA "Edit Commit Message" dialog.

See which Git commands were executed

To see which Git commands IntelliJ IDEA performed, open the “Console” tab in the Git window.

Using Git interactive rebase from the command line

Let’s take a look at how to use Git interactive rebase from the command line.

In the Git history, identify the commit just before the commit from where you want to clean up your history. In this example, that will be the last commit before we started adding the new feature.

Find the commit hash for this commit in the “Commit Details” to the right of the Git history in the Git window and copy this commit hash. (Spoiler: the commit hash in this example is 34bb0f99.)

IntelliJ IDEA Git history, showing the details of a selected commit, with the commit hash `34bb0f99` highlighted.

Open the Terminal window, using ⌥F12 on Mac (or Alt+F12 on Windows & Linux) and type git rebase -i 34bb0f99 (where 34bb0f99 is the commit hash we copied above).

Terminal with the command `git rebase -i 34bb0f99`

This will open an editor in the terminal with the list of commits that were done on top of the selected commit. Each line in this file is an individual commit.

Terminal with vi editor open, showing a list of commits.

By default, Git will use whatever you have set as your default text editor. If you haven’t set one, it will fall back to the vi editor, which is what we will use in this tutorial.

Changing the order of the commits

Let’s say we want to change the order of the commits; we want to keep the unrelated change, but separately from the changes for the new feature. We can do so by changing the order of the lines (individual commits) to reflect the order we want.

In the editor in the terminal, switch to edit mode by pressing I to be able to edit this file.

We can change the order of the lines by removing the commit we want to move from the list and inserting it in the place where we want it.

In vi, we can do so as follows:

  • Place the cursor anywhere on the line you want to move (in this example the commit “Unrelated changes”) and remove this line by typing dd.
  • Move the cursor to the line where you want to reinsert this commit (in this example, the end of the file) and type p.
  • Note: you do not need to switch to edit mode to do so.
Terminal with vi editor open, showing a list of commits. The bottom commit is highlighted.

Once we’re sure about the order, we need to save the file. Press esc to exit edit mode and type :wq to save the file.
Note: If you made changes to the file that you do not want to save, type :q! to force quit.

The interactive rebase will be applied. We see in the Git log that the order of the commits has changed.

Combining multiple commits into one commit

Next, we want to combine multiple commits where we added the tests and implemented the new feature. In the terminal, type git rebase -i 34bb0f99 to start rebasing. If you have already run this command, you can press the up arrow  in the terminal to show the last used command(s).

This will again open an editor in the terminal with the list of commits.

Switch to edit mode in the editor in the terminal. In vi, you can do so by pressing I.

For each of the commits we want to combine, replace “pick” with “fixup”.

Note that we use “fixup” because we want to use one commit message for the combination of the commits. Alternatively, we could use “squash” to combine the individual commit messages into the new commit message.

Terminal with vi editor open, showing a list of commits. For several commits `pick` is replaced with `fixup`.

Once we have correctly edited all the commits we want to combine, save the file.
In vi, press esc to exit edit mode and type :wq to save the file.
The interactive rebase will be applied. In the Git log, we can see that multiple individual commits are now combined into one commit with one commit message.

Drop a commit

Finally, we want to drop the commit with a mistake that we made. In the terminal, type git rebase -i 34bb0f99 to start rebasing.

To drop a commit, remove that commit from the list of commits. In this example, we will remove the commit “Mistake”.

In vi, we can remove a line by placing the cursor anywhere on the line we want to remove and typing dd. Alternatively, we can switch to edit mode by pressing I and removing the line manually. Press escto exit edit mode.

Terminal with vi editor open, showing a list of commits.

Save the file by typing :wq and the interactive rebase will be applied. We see in the Git log that the commit is dropped.

Summary

Now we know how to use git interactive rebase either from the IntelliJ IDEA UI or from the command line. Give them a try and use whichever way you prefer.

IntelliJ IDEA Shortcuts Used

Here are the IntelliJ IDEA shortcuts that we used.

NamemacOS ShortcutWindows / Linux Shortcut
Open the Git Tool Window⌘9Alt+9
Open the Commit Window⌘0Alt+0
Open the Terminal⌥F12Alt+F12
Select Fixup (in the “Rebasing Commits” popup)⌥F12Alt+F
Edit commit message (in the Git Log)F2F2
IntelliJ IDEA shortcuts

Git commands Used

Here are the Git commands that we used.

Nameterminal command
Git interactively rebase from a specific commit with commit hash, for example 11aa23bcgit rebase -i 11aa23bc
Use this commitpick
Fixup this commit (add changes to previous commit under the same commit message)fixup
Squash this commit (add changes to previous commit and combine commit messages)squash
Git commands

vi Shortcuts Used

Here are the shortcuts that we used.

NameShortcut
Open interactive (edit) modeI
Exit interactive (edit) modeesc
Remove line (note: not in edit mode)dd
Reinsert line (note: not in edit mode)p
Write and quit:wq
Force quit:q!
vi shortcuts

Related Links

Using Git interactive rebase in IntelliJ IDEA

Git interactive rebase allows you to change individual commits, squash commits together, drop commits or change the order of the commits. This allows you to clean up your git commit history to make it linear and meaningful, which can make it easier to understand the history of the project in the future. Let’s take a look at how this works.

For more information, see Using Git Interactive Rebase.

Getting started with Cucumber in Java — A 10 minute tutorial

This article was first published on Medium.

This tutorial will tell you how to get started with Cucumber-jvm in Java. It is intended as a brief, easy guide. For more examples on how to use Cucumber with Java or Kotlin, check the links at the bottom of this tutorial.

Prerequisites

To get started with Cucumber in Java, you will need the following:

  • Java SE — Java 8 (Java 9 is not yet supported by Cucumber)
  • Maven — Version 3.3.1 or higher
  • An IDE editor, for example IntelliJ IDEA (which will be used in this introduction; the community edition is free!)
  • A Cucumber plugin for your IDE, for example IntelliJ IDEA Cucumber for Java plugin to go with IntelliJ IDEA

Setting up the project

First, we need to set up the project so we can use Cucumber.

Create a Maven project

In this tutorial, we’re using Maven to import external dependencies. We start by creating a new Maven project, which will automatically create some of the directories and files we will need.

To create a new Maven project in IntelliJ IDEA:

  1. Click the menu option File > New > Project
  2. In the New project dialog box, select Maven on the left (if it isn’t already selected)
  3. Make sure that the Project SDK is selected (for instance, Java 1.8) and click Next
  4. Specify a GroupId and ArtifactId for your project and click Next
  5. Specify a Project name and Project location for your project (if needed) and click Finish

You should now have a project with the following structure:

├── pom.xml
└── src
├── main
│ └── java (marked as sources root)
│ └── resources (marked as resources root)
└── test
└── java (marked as test sources root)

Add Cucumber to your project

Add Cucumber to your project by adding a dependency to your pom.xml:

<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>

In addition, we need the following dependencies to run Cucumber with JUnit:

<dependencies>
...
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

If you have IntelliJ IDEA configured to auto-import dependencies, it will automatically import them for you. Otherwise, you can manually import them by opening the Maven Projects menu on the right and clicking the Reimport all Maven Projects icon on the top left of that menu. To check if your dependencies have been downloaded, you can open the External Libraries in the left Project menu in IntelliJ IDEA.

To make sure everything works together correctly, open a terminal and navigate to your project directory (the one containing the pom.xml file) and enter mvn clean test.

You should see something like the following:

[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building cucumber-tutorial 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------- <progress messages....>[INFO] -------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------
[INFO] Total time: <time> s
[INFO] Finished at: <date> <time>
[INFO] Final Memory: <X>M/<Y>M
[INFO] -------------------------------------------------------------

Your project builds correctly, but nothing is tested yet as you have not specified any behaviour to test against.

Specifying Expected Behaviour

We specify the expected behaviour by defining features and scenarios.

The feature describes (part of) a feature of your application, and the scenarios describe different ways users can use this feature.

Creating the Feature Directory

Features are defined in .feature files, which are stored in the src/test/resources/ directory (or a sub-directory).

We need to create this directory, as it was not created for us. In IntelliJ IDEA:

  1. In the Test folder, create a new directory called resources.
  2. Right click the folder and select Mark directory as > Test Resources Root.
  3. You can add sub-directories as needed. Create a sub-directory with the name of your project in src/test/resources/

Our project structure is now as follows:

├── pom.xml             (containing Cucumber and JUnit dependencies)
└── src
    ├── main
    │   └── java        (marked as sources root)
    │   └── resources   (marked as resources root)
    └── test
        ├── java        (marked as test sources root)
        └── resources   (marked as test resources root)
                └── <project>

Creating a Feature

To create a feature file:

  1. Open the project in your IDE (if needed) and right-click on the src/test/resources/<project> folder.
  2. Select New > File
  3. Enter a name for your feature file, and use the .feature extension. For instance, belly.feature.

Our project structure is now as follows:

├── pom.xml             (containing Cucumber and JUnit dependencies)
└── src
├── main
│ └── java (marked as sources root)
│ └── resources (marked as resources root)
└── test
├── java (marked as test sources root)
└── resources (marked as test resources root)
└── <project>
└── belly.feature

Files in this folder with an extension of .feature are automatically recognized as feature files. Each feature file describes a single feature, or part of a feature.

Open the file and add the feature description, starting with the Feature keyword and an optional description:

Feature: Belly
Optional description of the feature

Creating a Scenario

Scenarios are added to the feature file, to define examples of the expected behaviour. These scenarios can be used to test the feature. Start a scenario with the Scenario keyword and add a brief description of the scenario. To define the scenario, you have to define all of its steps.

Defining Steps

These all have a keyword (GivenWhen, and Then) followed by a step. The step is then matched to a step definition, which map the plain text step to programming code.

The plain text steps are defined in the Gherkin language. Gherkin allows developers and business stakeholders to describe and share the expected behaviour of the application. It should not describe the implementation.

The feature file contains the Gherkin source.

  • The Given keyword precedes text defining the context; the known state of the system (or precondition).
  • The When keyword precedes text defining an action.
  • The Then keyword precedes text defining the result of the action on the context (or expected result).

The scenario will look this:

Scenario: a few cukes
Given I have 42 cukes in my belly
When I wait 1 hour
Then my belly should growl

Running the test

To run the tests from JUnit we need to add a runner to our project.

Create a new Java class in your src/test/java/<project> directory, called RunCucumberTest.java:

package <project>;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"pretty"})
public class RunCucumberTest{
}

Our project structure is now as follows:

├── pom.xml             (containing Cucumber and JUnit dependencies)
└── src
├── main
│ └── java (marked as sources root)
│ └── resources (marked as resources root)
└── test
├── java (marked as test sources root)
│ └── <project>
│ └── RunCucumberTest.java
└── resources (marked as test resources root)
└── <project>
└── belly.feature

The JUnit runner will by default use classpath:package.of.my.runner to look for features. You can also specify the location of the feature file(s) and glue file(s) you want Cucumber to use in the @CucumberOptions.

You can now run your test by running this class. You can do so by right-clicking the class file and selecting RunCucumberTest from the context menu.

You should get something like the following result:

1 Scenarios (1 undefined)
3 Steps (3 undefined)
0m0.015s
You can implement missing steps with the snippets below:@Given("^I have (\\d+) cukes in my belly$")
public void i_have_cukes_in_my_belly(int arg1) throws Exception {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}@When("^I wait (\\d+) hour$")
public void i_wait_hour(int arg1) throws Exception {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}@Then("^my belly should growl$")
public void my_belly_should_growl() throws Exception {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
Process finished with exit code 0

As we can see, our tests have run, but have not actually done anything — because they are not yet defined.

Define Snippets for Missing Steps

We now have one undefined scenario and three undefined steps. Luckily, Cucumber has given us examples, or snippets, that we can use to define the steps.

To add them to a Java class in IntelliJ IDEA:

  1. Create a new Java class in your src/test/java/<project> folder (for instance, StepDefinitions.java)
  2. Paste the generated snippets into this class

IntelliJ IDEA will not automatically recognize those symbols (like @Given@When@Then), so we’ll need to add import statements. In IntelliJ IDEA:

  • Add import statements for @Given@When@Then (underlined in red)

In IntelliJ IDEA you can do so by putting your cursor on the @Given symbol and press ALT + ENTER, then select Import class.

Our project structure is now as follows:

├── pom.xml             (containing Cucumber and JUnit dependencies)
└── src
├── main
│ └── java (marked as sources root)
│ └── resources (marked as resources root)
└── test
├── java (marked as test sources root)
│ └── <project>
│ └── RunCucumberTest.java
│ └── StepDefinitions.java
└── resources (marked as test resources root)
└── <project>
└── belly.feature

Now, when you run the test, these step definitions should be found and used.

Note: Run configurations

If this does not work, select Run > Edit Configurations, select Cucumber java from the Defaults drop-down, and add the project name to the Glue field on the Configuration tab.

Your result will include something like the following:

cucumber.api.PendingException: TODO: implement me
at skeleton.Stepdefs.i_have_cukes_in_my_belly(Stepdefs.java:10)
at ✽.I have 42 cukes in my belly(/Users/maritvandijk/IdeaProjects/cucumber-java-skeleton/src/test/resources/skeleton/belly.feature:4)

The reason for this is that we haven’t actually implemented this step; it throws a PendingException telling you to implement the step.

Implement the steps

We will need to implement all steps to actually do something.

  • Update your StepDefinitions.java class to implement the step definition.

The step can be implemented like this:

@Given("^I have (\\d+) cukes in my belly$")
public void I_have_cukes_in_my_belly(int cukes) throws Throwable {
Belly belly = new Belly();
belly.eat(cukes);
}

To make this step compile we also need to implement a class Belly with a method eat().

  • Implement the class Belly.java inside your src/main/java/<project> folder; create your <project> directory here (if needed)

Our project structure is now as follows:

├── pom.xml             (containing Cucumber and JUnit dependencies)
└── src
├── main
│ └── java (marked as sources root)
│ │ └── <project>
│ └── Belly.java
│ └── resources (marked as resources root)
└── test
├── java (marked as test sources root)
│ └── <project>
│ └── RunCucumberTest.java
│ └── StepDefinitions.java
└── resources (marked as test resources root)
└── <project>
└── belly.feature

Now you run the test and implement the code to make the step pass. Once it does, move on to the next step and repeat!

PendingException

Once you have implemented this step, you can remove the statement throw new PendingException(); from the method body. The step should no longer thrown a PendingException, as it is no longer pending.

Result

Once you have implemented all your step definitions (and the expected behaviour in your application!) and the test passes, the summary of your results should look something like this:

Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.656 secResults :Tests run: 5, Failures: 0, Errors: 0, Skipped: 0[INFO] -------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------
[INFO] Total time: 5.688 s
[INFO] Finished at: 2017-05-22T15:43:29+01:00
[INFO] Final Memory: 15M/142M
[INFO] -------------------------------------------------------------

Examples

To get started with a working project, try the cucumber-java skeleton project which is available from GitHub.

For more examples of how to use Cucumber, have a look at the examples provided in the cucumber-jvm project on GitHub.

If you’d like to try Cucumber with Kotlin, have a look at my blog post.

Note: This tutorial was originally written as part of the new Cucumber documentation. You can find the cucumber documentation project on GitHub. It was adapted a little here to make a stand-alone tutorial.

Kukumber — Getting started with Cucumber in Kotlin

This article was first published on Medium.

My team is creating an application in Kotlin. To make development of Cucumber tests easier, we decided to also use Cucumber-jvm with Kotlin instead of Java. Fortunately, it is possible to use cucumber-java8 in Kotlin (kotlin-java8)

Prerequisites

If you’d like to follow along, make sure you have the following installed:

Add dependencies

We use Maven, so we added the following dependencies to our pom.xml:

Maven dependencies for Cucumber-jvm

Note: The cucumber-junit dependency is added so we can add a JUnit Runner to run our tests, which we will do later.

If you don’t have Kotlin already configured in your project, you’ll need to add those dependencies also (or have IntelliJ IDEA do it for you).

Add a feature file

In our src/test/resources folder we create a new directory and add a .feature file. For this example, we’ll reuse the belly.feature from the cucumber-java-skeleton

Feature file `belly.feature`

Unfortunately the IntelliJ IDEA Cucumber plugin does not (yet) support a link between the steps in our feature file and our step definitions, like it does for Java. Also, we cannot generate snippets in Kotlin directly. Fortunately there is a work around: we can run the tests to generate snippets in Java 8 lambda style.

You can run the test from IntelliJ IDEA by right-clicking the feature file and selecting “Run ‘Feature:belly’” from the context menu.

When you run the tests, you should get something like the following result:

Generated snippets

Add Step Definitions

In the src/test/kotlin folder, we add a new Kotlin File/Class, called `StepDefs`.

We only have to write a little Kotlin code in the file:

Create StepDefs.kt

Note that our StepDefs implement the `cucumber.api.java8.En` interface, so we need to import it.

Now, when we copy-paste the generated snippets inside the `init{}` block, IntelliJ IDEA offers to convert it to Kotlin for us. Once we do, we will also need to import the `cucumber.api.PendingException` mentioned in the snippets.

Now we have the following StepDefs.kt file and we can start implementing the steps, as well as the code to make them pass!

Add snippets to StepDefs.kt

To run our features from a JUnit runner, we’ll need to add one. In the src/test/kotlin folder, we add a new Kotlin File/Class, called RunKukesTest.

RunKukesTest.kt

This code is available on GitHub: https://github.com/mlvandijk/kukumber-skeleton