diff --git a/README.md b/README.md index c59fae7..02ed082 100644 --- a/README.md +++ b/README.md @@ -4,118 +4,36 @@ [![GitHub version](https://badge.fury.io/gh/jApprove%2Fjapprove.svg)](http://badge.fury.io/gh/jApprove%2Fjapprove) ![License](https://img.shields.io/badge/License-Apache%20License%202.0-brightgreen.svg) -An extension of JUnit5 that enables approval testing for Java-based software. - -## Features - -Currently, this Approval Testing framework contains the following features: +jApprove is a testing tool that provides an easy and flexible way to use approval testing in Java-based software. The basic idea of this tool is to extend JUnit 5 to obtain familiar test cases and to use standard build tools to highlight and approve changes. The main focus of this tool is on the test of large JSON objects and REST APIs. -- Approval Testing of Strings and JSON Objects -- Approval Testing of REST APIs -- Highlighting differences -- Approving changes +### Features -## Usage +Currently, jApprove contains the following features: -1. Use the jApprove Dependency that is located on the Maven Central Repository in the following way: +* Approval Testing of Strings and JSON Objects +* Straightforward execution of the tests from inside an IDE +* Simple approving and diffing functionality by the usage of Gradle or Maven +* Run Approval Tests in a CI Pipeline +* Modular structure to simply replace components or add new features - ``` - repositories { - mavenCentral() - } - dependencies { - testImplementation("org.japprove:japprove-core:1.2.0") - } - ``` -2. Use the jApprove Gradle Plugin in the following way: +### Getting Started - ``` - buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("org.japprove:japprove-gradle-plugin:1.2.0") - } - } +The usage of jApprove depends on the build tool that is used. Therefore, there are tutorials for Gradle- and Maven-based projects. - apply plugin: 'differ-plugin' - apply plugin: 'approver-plugin' - ``` +* [Getting Started with Gradle](documentation/gradle-documentation.md) +* [Getting Started with Maven](documentation/maven-documentation.md) -3. Add an Approval Test: - ``` - @ApprovalTest(baseline="sorting1") - void testSortNames(StringVerifier stringVerifier) { - // arrange - List names = Arrays.asList("Peter", "Mike", "John"); - - // act - StringSorter sorter = new StringSorter(); - names = sorter.sort(names); - - // approve - stringVerifier.verify(names); - } - ``` +### Examples -4. Run the test to check whether there are changes comparing to a previously approved version. In the case there are changes, they are printed in the error message. +For both Gradle and also Maven there is an example project that uses jApproval to demonstrate the usage. - Note: If there is no approved version, the test fails anyway. In this case you first have to approve the current version. +* [Gradle Example Project](https://github.com/jApprove/japprove-gradle-example) +* [Maven Example Project](https://github.com/jApprove/japprove-maven-example) -5. Approve the failing tests with the following command: - `gradle approve` - - During a starting batch process it is possible to see all changes and approve each failing test. - - To approve the changes of all failing test at once, use the following command: - `gradle approve --all` - To approve the changes of a specific failing test, use for example: - `gradle approve --baseline=sorting1` - -6. To get a better overview of all changes, it is possible to highlight the changes of a failing test within an external diff tool. Use for example: - - `gradle diff --baseline=sorting1` - -7. Customize jApprove properties (optional): - - Create a "japprove.properties" file in the "src/main/resources" directory. In this file it is possible to specify the following values: - - - The directory of the baseline - - The temporary directory of the unapproved files - - A custom diff tool - - For example, the properties file could look like the following one: - - ``` - baselineDirectory=baselines\\ - baselineCandidateDirectory=build\\baselineCandidates\\ - diffTool=C:\\Program Files\\JetBrains\\IntelliJ IDEA Community Edition 2019.2.3\\bin\\idea64 diff - ``` - - The properties of the file above are the default properties. - - -## Components - -This project consists of a core library, a gradle plugin and an example that demonstrates the functionality. - -### jApprove Core - -The core part of this tool is an extension of the jUnit testing framework. It enables to use the @ApprovalTest annotation to mark a test as an approval test and run them like usual unit tests. - - -### jApprove Gradle Plugin - -A gradle plugin that automates the "diff" and "approve" steps. - -### jApprove Example - -Uses the testing framework and the plugin to demonstrate the functionality on a simple example. diff --git a/documentation/gradle-documentation.md b/documentation/gradle-documentation.md new file mode 100644 index 0000000..fc4217e --- /dev/null +++ b/documentation/gradle-documentation.md @@ -0,0 +1,159 @@ +### Getting Started with Gradle + +This tutorial explains the necessary steps to use jApprove in a Gradle project. + +#### Setup + +To use the entire functionality of jApprove, it is necessary to add the jApprove dependency and the Gradle-Plugin to your project's build.gradle. + +```groovy +repositories { + mavenCentral() +} +dependencies { + implementation("org.japprove:japprove-core:1.2.0") +} +``` + +```groovy +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.japprove:japprove-gradle-plugin:1.2.0") + } +} + +apply plugin: 'differ-plugin' +apply plugin: 'approver-plugin' +``` + + +#### Create a Simple Test + +Although the main focus of jApprove is on JSON objects and API tests, this simple example should demonstrate how jApprove basically works. Therefore, a simple method that formats a list of strings is used. For each string that occurs in the list leading and trailing spaces are removed, all letters are converted to lower case and the first letter is converted to upper case. + +```java +public class StringFormatter { + + public static List format(List strings) { + List formattedStrings = new ArrayList<>(); + for (String s : strings) { + s = s.trim(); + s = s.toLowerCase(); + s = s.substring(0, 1).toUpperCase() + s.substring(1); + formattedStrings.add(s); + } + return formattedStrings; + } +} +``` + +Now, this method is tested by the usage of jApprove. An approval test is simply created by annotating the method under test with @ApprovalTest and pass the StringVerifier as a parameter. The actual test looks very similar to a usual JUnit test using the Arrange, Act and Assert (AAA) Pattern. The crucial difference is the final step where the verifier is called instead of asserting. The verifier reads the content of the string and compares it to a previously approved version. This version is stored in the so-called _baseline_ that can be set as a parameter of the @ApprovalTest annotation. If no parameter is set, a random name is used. Currently, this tool uses a text-based approach and therefore the baseline is just a simple text file. + +```java +public class StringFormatterTest { + + @ApprovalTest(baseline = "strings") + void testFormat(StringVerifier stringVerifier) { + // arrange + List names = Arrays.asList("PETER", "MiKe", "joHn", " pAuL "); + + // act + List formattedNames = StringFormatter.format(names); + + // approve + stringVerifier.verify(formattedNames); + } +} +``` + +The test can be started like a usual JUnit test (e.g. by clicking a button within an IDE). Because there is no approved version, the test obviously fails the first time. As a side effect, the file _simpleSorting.txt_ has been created in the _build/baselineCandidates/_ directory. This directory is used to store all unapproved versions. To approve this version, use the following command: + +`gradle approve --baseline=strings` + +With the `gradle approve` command the approve function of the Gradle-Plugin is called. The --baseline option is used to specify the baseline of the respective test case. In this case `--baseline=strings`. + +Finally, if the test is started again, it passes successfully. Meanwhile, the file _simpleSorting.txt_ has been moved from _build/baselineCandidates/_ directory to a new _baselines/_ directory where all approved versions are stored. + +If you make some changes to the the code (e.g. refactoring, remodularization, ...), you can simply rerun the test to verify that the behaviour of the method is still the same. If there are changes, the test fails and the the error message shows the differences. At this point you are also able to approve the new version, if the changes are accepted or even desired. + +If there are many changes or a large output, it is possible to inspect the differences with the aid of an external diff tool. This tool has to be configured in the japprove.properties file that is located in the _src/test/resources/_ directory. For example, the properties file could look like the following one: + +``` +diffTool=C:/Program Files/KDiff3/kdiff3.exe diff +``` + +To call this tool, use the following command: + +`gradle diff --baseline=strings` + + +#### Create a Test for a JSON Object + +The test of JSON objects is very similar to the test of strings. But nevertheless, there are a few differences. To demonstrate them, a simple method that returns a simple mock state is used. The state is returned as JsonNode and consists of the actual state and a simple timestamp. + +```java +public class SimpleState { + + public static JsonNode getState() { + String json = "{\"state\" : \"OK\"," + "\"timestamp\" : \"1579622991\"}"; + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = null; + try { + jsonNode = objectMapper.readTree(json); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return jsonNode; + } +} +``` + +To create an Approval Test for this state, it is necessary to pass a JsonVerifier instead of a StringVerifier. The JsonVerifier is designed for JsonObjects and consists of a separate implementation. That means, for example, the order of the nodes does not matter and the test passes even if you change the order. Furthermore, it enables to ignore elements of the JSON object. For example a timestamp that is different every time the test is started can simply be excluded from the test by the usage of the ignore method. + +```java +public class SimpleStateTest { + + @ApprovalTest(baseline = "json") + public void testGetState(JsonVerifier jsonVerifier) { + JsonNode state = SimpleState.getState(); + jsonVerifier.ignore("timestamp").verify(state); + } +} +``` + +The usage of the JsonVerifier also enables testing REST APIs in the case they return JSON objects. + + +#### Customize jApprove properties (optional): + +By default the the approved files are stored in a _baselines/_ directory and the unapproved files in a _build/baselineCandidates/_ directory. If other locations are desired, they can be changed in the japprove.properties file in the _src/test/resources/_ directory. For example, the properties file could look like the following one: + +``` +baselineDirectory=approvedFiles +baselineCandidateDirectory=build\\unapprovedFiles +``` + + +#### Basic Commands + +* Approve a failing test with the following command: + + `gradle approve --baseline=${testname}` + +* Approve the changes of all failing test at once with the following command: + + `gradle approve --all` + +* Start a batch process and approve/diff all failing tests step by step with the following command: + + `gradle approve` + +* Highlight the differences within an external diff tool with the following command: + + `gradle diff --baseline=${testname}` + + + \ No newline at end of file diff --git a/documentation/maven-documentation.md b/documentation/maven-documentation.md new file mode 100644 index 0000000..4cc678f --- /dev/null +++ b/documentation/maven-documentation.md @@ -0,0 +1,175 @@ +### Getting Started with Maven + +This tutorial explains the necessary steps to use jApprove in a Maven project. + +#### Setup + +To use the entire functionality of jApprove, it is necessary to add the jApprove dependency and the Maven-Plugin to your project's pom.xml. + +```xml + + + org.japprove + japprove-core + 1.2.0 + + +``` + +```xml + + + + org.japprove + japprove-maven-plugin + 1.2.0 + + + + approve + + + + + + +``` + +To simplify the Maven commands of the plugin, it is also recommended to add the plugin group to your settings.xml (usually located in the _${user.home}/.m2/_ directory). + +```xml + + + org.japprove + + +``` + + +#### Create a Simple Test + +Although the main focus of jApprove is on JSON objects and API tests, this simple example should demonstrate how jApprove basically works. Therefore, a simple method that formats a list of strings is used. For each string that occurs in the list leading and trailing spaces are removed, all letters are converted to lower case and the first letter is converted to upper case. + +```java +public class StringFormatter { + + public static List format(List strings) { + List formattedStrings = new ArrayList<>(); + for (String s : strings) { + s = s.trim(); + s = s.toLowerCase(); + s = s.substring(0, 1).toUpperCase() + s.substring(1); + formattedStrings.add(s); + } + return formattedStrings; + } +} +``` + +Now, this method is tested by the usage of jApprove. An approval test is simply created by annotating the method under test with @ApprovalTest and pass the StringVerifier as a parameter. The actual test looks very similar to a usual JUnit test using the Arrange, Act and Assert (AAA) Pattern. The crucial difference is the final step where the verifier is called instead of asserting. The verifier reads the content of the string and compares it to a previously approved version. This version is stored in the so-called _baseline_ that can be set as a parameter of the @ApprovalTest annotation. If no parameter is set, a random name is used. Currently, this tool uses a text-based approach and therefore the baseline is just a simple text file. + +```java +public class StringFormatterTest { + + @ApprovalTest(baseline = "strings") + void testFormat(StringVerifier stringVerifier) { + // arrange + List names = Arrays.asList("PETER", "MiKe", "joHn", " pAuL "); + + // act + List formattedNames = StringFormatter.format(names); + + // approve + stringVerifier.verify(formattedNames); + } +} +``` + +The test can be started like a usual JUnit test (e.g. by clicking a button within an IDE). Because there is no approved version, the test obviously fails the first time. As a side effect, the file _simpleSorting.txt_ has been created in the _build/baselineCandidates/_ directory. This directory is used to store all unapproved versions. To approve this version, use the following command: + +`mvn japprove:approve -Dbaseline=strings` + +With the `mvn japprove:approve` command the approve function of the Maven-Plugin is called. The -D option is used to specify the baseline of the respective test case. In this case `-Dbaseline=strings`. + +Finally, if the test is started again, it passes successfully. Meanwhile, the file _simpleSorting.txt_ has been moved from _build/baselineCandidates/_ directory to a new _baselines/_ directory where all approved versions are stored. + +If you make some changes to the the code (e.g. refactoring, remodularization, ...), you can simply rerun the test to verify that the behaviour of the method is still the same. If there are changes, the test fails and the the error message shows the differences. At this point you are also able to approve the new version, if the changes are accepted or even desired. + +If there are many changes or a large output, it is possible to inspect the differences with the aid of an external diff tool. This tool has to be configured in the japprove.properties file that is located in the _src/test/resources/_ directory. For example, the properties file could look like the following one: + +``` +diffTool=C:/Program Files/KDiff3/kdiff3.exe diff +``` + +To call this tool, use the following command: + +`mvn japprove:diff -Dbaseline=strings` + + +#### Create a Test for a JSON Object + +The test of JSON objects is very similar to the test of strings. But nevertheless, there are a few differences. To demonstrate them, a simple method that returns a simple mock state is used. The state is returned as JsonNode and consists of the actual state and a simple timestamp. + +```java +public class SimpleState { + + public static JsonNode getState() { + String json = "{\"state\" : \"OK\"," + "\"timestamp\" : \"1579622991\"}"; + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = null; + try { + jsonNode = objectMapper.readTree(json); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return jsonNode; + } +} +``` + +To create an Approval Test for this state, it is necessary to pass a JsonVerifier instead of a StringVerifier. The JsonVerifier is designed for JsonObjects and consists of a separate implementation. That means, for example, the order of the nodes does not matter and the test passes even if you change the order. Furthermore, it enables to ignore elements of the JSON object. For example a timestamp that is different every time the test is started can simply be excluded from the test by the usage of the ignore method. + +```java +public class SimpleStateTest { + + @ApprovalTest(baseline = "json") + public void testGetState(JsonVerifier jsonVerifier) { + JsonNode state = SimpleState.getState(); + jsonVerifier.ignore("timestamp").verify(state); + } +} +``` + +The usage of the JsonVerifier also enables testing REST APIs in the case they return JSON objects. + + +#### Customize jApprove properties (optional): + +By default the the approved files are stored in a _baselines/_ directory and the unapproved files in a _build/baselineCandidates/_ directory. If other locations are desired, they can be changed in the japprove.properties file in the _src/test/resources/_ directory. For example, the properties file could look like the following one: + +``` +baselineDirectory=approvedFiles +baselineCandidateDirectory=build\\unapprovedFiles +``` + + +#### Basic Commands + +* Approve a failing test with the following command: + + `mvn japprove:approve -Dbaseline=${testname}` + +* Approve the changes of all failing test at once with the following command: + + `mvn japprove:approve -Dall` + +* Start a batch process and approve/diff all failing tests step by step with the following command: + + `mvn japprove:approve` + +* Highlight the differences within an external diff tool with the following command: + + `mvn japprove:diff -Dbaseline=${testname}` + + + \ No newline at end of file