This repository is a template project for building a Java test client that can be run independently from its test target. This pattern of testing is typically referred to as end-to-end (E2E) integration testing. This test client uses the JUnit 5 (Jupiter) test engine to run Cucumber-defined tests. Cucumber is a behavior-driven development (BDD) testing framework that allows tests to be written in plain English. This allows non-developers to write tests that can be run by developers. The Cucumber tests are written in the Gherkin language, which is a plain-text language that is easy to understand and write. The build of this project is built for Github and Github Actions CI/CD pipeline. If you use this project as a template and you want to use a different CI/CD pipeline, you will need to modify the build.gradle.kts file to accommodate your pipeline. All the Github Actions workflows are in the .github/workflows directory so if you are not using Github Actions, you can delete this directory when you create your own repository from this template.
The purpose of this test client is to implement end-to-end tests that exercise APIs with tests developed from a "black-box" perspective. This means that the only knowledge the test client has about it's target is the APIs and/or other external interfaces that the target makes public. These kinds of tests not only test from the end-user's perspective, but they also can be used to valid the target and all its run-time dependencies regardless of environments (pre-production and/or production). In addition, the tests needed to be packaged in a fully-standalone client that can be run in a headless environment (e.g., CI/CD pipeline). This requires a testing framework that can be run in a headless environment and is as light-weight as possible.
After looking at many testing frameworks, we decided to use Cucumber for the following reasons:
- Open Source: Cucumber is an open-source testing framework that is widely used in the industry.
- Behavior-Driven Development (BDD): Cucumber is a BDD testing framework that allows tests to be written in plain English. This allows non-developers to write tests that can be run by developers.
- Light-Weight: Cucumber is a light-weight testing framework that is easy to use and understand by developers and doesn't require a large number of dependencies to be packaged with it.
- Integration with JUnit 5: Cucumber integrates with JUnit 5, which is the latest version of the JUnit testing framework. You can use the JUnit Platform Launcher to run Cucumber tests in a headless environment.
Other evaluated frameworks such as TestNG and Karate were too heavy-weight for our needs with too many dependencies making the final test client package too large.
Normally, when using Cucumber in a Java project, the Cucumber tests are run as part of the Maven or Gradle build process, are located in the src/test directory structure, and are integrated with the IDE. Because the E2E tests in this repository are separately maintained from the target, they are found in the src/main directory of the project instead of the normal src/test location. This approach makes it easier for Gradle to find all the dependencies and package them into a single JAR file that can be run in a headless environment. While there are unit tests (JUnit 5) in the src/test directory, their target is the test client itself while the Cucumber tests in the src/main directory target the external APIs for their tests. So all the feature files and step definition classes for the E2E tests should be in the src/main directory.
- Java 17 or later
- Download the latest version of the test client JAR,
test-client-<version>-shaded.jar, from the packages page by clicking on theinfo.rx00405.test-clientpackage and downloading the shaded JAR file from theAssetslist of links on the right side of the page. - Create a personal access token (classic) in Github by following the instructions here. The tests in this template do not require write privileges to Github, so you can create a token with read-only privileges.
NOTE: The tests call the Github GraphQL API, which requires an access token to authenticate the user. For some reason, API access requires the classic version of a personal access token. Make sure you are careful about storing and using your access token. Do NOT save it in configuration files or hard-code it in your code. That is a security issue (compromised secrets). Instead, use environment variables or a secret manager to store and retrieve the access token and pass it into the test client as a command-line argument.
- Store the access token locally in a secure manner so that it can be retrieved when running the test client.
- Open a terminal window and navigate to the directory where the test client was downloaded
- Since the test client is an executable JAR file, it can be run using the following command:
java -jar test-client-<version>-shaded.jar --token=<Github Personal Access Token>- Java 17 or later
- Gradle 8.10 or later
- Clone the repository to your local machine
- Open a terminal window and navigate to the root directory of the cloned repository
- Build the test client using the following command:
./gradlew clean build- If you want
gradleto run the test client as part of it's execution, you can use the following command:
./gradlew clean build testClient -PtestClientArgs="--token=<Github Personal Access Token>"- Java 17 or later
- Gradle 8.10 or later
- A recent version of Git
- An IDE that supports Java development (we like VSCode but you can use others like IntelliJ IDEA, Eclipse, etc.)
- Click on the
Use this templatebutton on the Github repository page to create a new repository based on this template in your own organization or personal account. - Follow the instructions in the previous section to clone the repository to your local machine but clone your new repository instead of the template repository.
- Refactor the package names of the code to match your organization's naming conventions.
- Open the cloned repository in your IDE and start developing your own tests in the test client. Start by adding new
featurefiles in new subdirectories under thesrc/main/resources/<your package path>/featuresdirectory and adding newstep definitionclasses in a matching subdirectory of thefeaturefiles in thesrc/main/java/<your package path>/test/client/testsdirectory. Utility classes that help call APIs and parse responses should be added to thesrc/main/java/<your package path>/test/client/utilsdirectory. Always work in this order: 1.featurefiles, 2.step definitionclasses, and 3. utility classes. This is the Cucumber BDD development cycle. - Add the
@Timedannotation to anystep definitionmethods that you want to monitor the performance in addition to the success of the test. - Lather, rinse and repeat until you have all the tests you need to validate your target.
java -jar [PATH to JAR/]test-client-<version>-shaded.jar [--run-quiet] [--iso-feature <iso-feature>] [--token <access-token>] [--help]--run-quiet
Run in quiet mode. The client will not print any output to standard out.
--iso-feature <iso-feature>
Run only the feature in the package indicated by the
<iso-feature>argument.
--token <access-token>
Use the
<access-token>to authenticate with the system under test for certain scenarios.
--help
Print the help message.
- io.freefair.aspectj.post-compile-weaving
- com.github.johnrengelman.shadow
- jacoco
- org.junit.jupiter:junit-jupiter
- org.junit.jupiter:junit-jupiter
- org.junit.jupiter:junit-jupiter-api
- org.junit.platform:junit-platform-launcher
- org.junit.platform:junit-platform-suite-api
- io.cucumber:cucumber-java
- io.cucumber:cucumber-junit-platform-engine
- org.apache.httpcomponents.client5:httpclient5-fluent
- org.slf4j:slf4j-api
- org.slf4j:slf4j-simple
- com.google.code.gson:gson
- commons-validator:commons-validator
- org.aspectj:aspectjrt
- org.aspectj:aspectjweaver
- com.graphql-java:graphql-java-extended-validation