Skip to content

Commit 916323d

Browse files
authored
Extract jackson module, introduce snapshot.properties (#66)
Co-authored-by: Jack Matthews <[email protected]>
1 parent a2f35ce commit 916323d

File tree

50 files changed

+778
-326
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+778
-326
lines changed

Diff for: README.md

+57-33
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,26 @@ Then java-snapshot-testing might just be what you are looking for!
1616
## Quick Start (Junit5 + Gradle example)
1717
1. Add test dependencies
1818
```groovy
19+
// In this case we are using the JUnit5 testing framework
1920
testImplementation 'io.github.origin-energy:java-snapshot-testing-junit5:2.+'
21+
22+
// Many will want to serialize into JSON. In this case you should also add the Jackson plugin
23+
testImplementation 'io.github.origin-energy:java-snapshot-testing-plugin-jackson:2.+'
2024
testImplementation 'com.fasterxml.jackson.core:jackson-core:2.11.3'
2125
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3'
2226
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.3'
2327
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3'
28+
29+
// slf4j logging implementation if you don't already have one
30+
testImplementation("org.slf4j:slf4j-simple:2.0.0-alpha0")
2431
```
2532

2633
2. Create `snapshot.properties` and configure your global settings. Be sure to set `output-dir` appropriately for you JVM language.
2734

2835
- /src/test/java/resources/snapshot.properties
2936
```text
3037
serializer=au.com.origin.snapshots.serializers.ToStringSnapshotSerializer
38+
serializer.json=au.com.origin.snapshots.serializers.DeterministicJacksonSnapshotSerializer
3139
comparator=au.com.origin.snapshots.comparators.PlainTextEqualsComparator
3240
reporters=au.com.origin.snapshots.reporters.PlainTextSnapshotReporter
3341
snapshot-dir=__snapshots__
@@ -44,6 +52,17 @@ public class MyFirstSnapshotTest {
4452
public void helloWorldTest() {
4553
expect("Hello World").toMatchSnapshot();
4654
}
55+
56+
@Test
57+
public void jsonSerializationTest() {
58+
Map<String, Object> map = new HashMap<>();
59+
map.put("name", "John Doe");
60+
map.put("age", 40);
61+
62+
expect(map)
63+
.serializer("json")
64+
.toMatchSnapshot();
65+
}
4766
}
4867
```
4968

@@ -79,16 +98,17 @@ We currently support:
7998
- [JUnit5](https://search.maven.org/search?q=a:java-snapshot-testing-junit5)
8099
- [Spock](https://search.maven.org/search?q=a:java-snapshot-testing-spock)
81100

82-
In addition - for `.json()` tests, you need jackson on your classpath
83-
84-
Gradle example
85-
```groovy
86-
// Required java-snapshot-testing peer dependencies
87-
testImplementation 'com.fasterxml.jackson.core:jackson-core:2.11.3'
88-
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3'
89-
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.3'
90-
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3'
91-
```
101+
Plugins
102+
- [Jackson for JSON serialization](https://search.maven.org/search?q=a:java-snapshot-testing-plugin-jackson)
103+
- You need jackson on your classpath
104+
Gradle example
105+
```groovy
106+
// Required java-snapshot-testing peer dependencies
107+
testImplementation 'com.fasterxml.jackson.core:jackson-core:2.11.3'
108+
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3'
109+
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.3'
110+
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3'
111+
```
92112
93113
## How does it work?
94114
1. When a test runs for the first time, a `.snap` file is created in a `__snapshots__` sub-directory
@@ -104,8 +124,7 @@ A text representation of your java object (toString() or JSON).
104124
105125
**String snapshot example**
106126
```java
107-
// `.string()` is the default so not strictly required (unless you override the default!)
108-
expect("hello world", "Hello world again!").string().toMatchSnapshot();
127+
expect("hello world", "Hello world again!").toMatchSnapshot();
109128
```
110129
```text
111130
au.com.example.company.HelloWorldTest.helloWorld=[
@@ -116,7 +135,7 @@ Hello world again!
116135

117136
**JSON Snapshot Example**
118137
```java
119-
expect(userDto).json().toMatchSnapshot();
138+
expect(userDto).serializer("json").toMatchSnapshot();
120139
```
121140
```text
122141
au.com.example.company.UserEndpointTest.shouldReturnCustomerData=[
@@ -229,18 +248,20 @@ Often your IDE has an excellent file comparison tool.
229248
## snapshot.properties (required as of v2.4.0)
230249
This file allows you to conveniently setup global defaults
231250

232-
| key | Description |
233-
|--------------|--------------------------------------------------------------------------------------------------|
234-
|serializer | Class name of the [serializer](#supplying-a-custom-snapshotserializer) |
235-
|comparator | Class name of the [comparator](#supplying-a-custom-snapshotcomparator) |
236-
|reporters | Comma separated list of class names to use as [reporters](#supplying-a-custom-snapshotreporter) |
237-
|snapshot-dir | Name of sub-folder holding your snapshots |
238-
|output-dir | Base directory of your test files (although it can be a different directory if you want) |
239-
|ci-env-var | Name of environment variable used to detect if we are running on a Build Server |
251+
| key | Description |
252+
|------------------|----------------------------------------------------------------------------------------------------------------|
253+
|serializer | Class name of the [serializer](#supplying-a-custom-snapshotserializer), default serializer |
254+
|serializer.{name} | Class name of the [serializer](#supplying-a-custom-snapshotserializer), accessible via `.serializer("{name}")` |
255+
|comparator | Class name of the [comparator](#supplying-a-custom-snapshotcomparator) |
256+
|reporters | Comma separated list of class names to use as [reporters](#supplying-a-custom-snapshotreporter) |
257+
|snapshot-dir | Name of sub-folder holding your snapshots |
258+
|output-dir | Base directory of your test files (although it can be a different directory if you want) |
259+
|ci-env-var | Name of environment variable used to detect if we are running on a Build Server |
240260

241261
For example:
242262
```text
243263
serializer=au.com.origin.snapshots.serializers.ToStringSnapshotSerializer
264+
serializer.json=au.com.origin.snapshots.serializers.DeterministicJacksonSnapshotSerializer
244265
comparator=au.com.origin.snapshots.comparators.PlainTextEqualsComparator
245266
reporters=au.com.origin.snapshots.reporters.PlainTextSnapshotReporter
246267
snapshot-dir=__snapshots__
@@ -279,30 +300,34 @@ The serializer determines how a class gets converted into a string.
279300

280301
Currently, we support three different serializers
281302

282-
| Serializer | Alias | Description |
283-
|----------------------------------------|----------------|-----------------------------------------------------------------------------------------------------------------------------|
284-
| ToStringSnapshotSerializer (default) | .string() | uses the `toString()` method |
285-
| JacksonSnapshotSerializer | .json() | uses [jackson](https://github.com/FasterXML/jackson) to convert a class to a snapshot |
286-
| DeterministicJacksonSnapshotSerializer | .orderedJson() | extension of JacksonSnapshotSerializer that also orders Collections for situations where the order changes on multiple runs |
287-
| Base64SnapshotSerializer | | use for images or other binary sources that output a `byte[]`. The output is encoded to Base64 |
303+
### Shipped with core
304+
| Serializer | Description |
305+
|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
306+
| ToStringSnapshotSerializer | uses the `toString()` method |
307+
| Base64SnapshotSerializer | use for images or other binary sources that output a `byte[]`. The output is encoded to Base64 |
308+
309+
### Shipped with Jackson plugin
310+
| Serializer | Description |
311+
|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
312+
| JacksonSnapshotSerializer | uses [jackson](https://github.com/FasterXML/jackson) to convert a class to a snapshot |
313+
| DeterministicJacksonSnapshotSerializer | extension of JacksonSnapshotSerializer that also orders Collections for situations where the order changes on multiple runs |
288314

289315
Serializers are pluggable, so you can write you own by implementing the `SnapshotSerializer` interface.
290316

291317
Serializers are resolved in the following order.
292-
- (method level) explicitly `expect(...).serializer(ToStringSerializer.class).toMatchSnapshot();`
318+
- (method level) explicitly `expect(...).serializer(ToStringSerializer.class).toMatchSnapshot();` or via property file `expect(...).serializer("json").toMatchSnapshot();`
293319
- (class level) explicitly `@UseSnapshotConfig` which gets read from the `getSerializer()` method
294-
- (properties) explicitly via snapshot.properties
295-
- (global) implicitly via `SnapshotConfig` default for your test framework
320+
- (properties) implicitly via `snapshot.properties`
296321

297322
```java
298323
@ExtendWith(SnapshotExtension.class)
299324
@UseSnapshotConfig(LowercaseToStringSnapshotConfig.class)
300325
public class SnapshotExtensionUsedTest {
301-
326+
302327
@Test
303328
public void aliasMethodTest() {
304329
expect(new TestObject())
305-
.orderedJson() // <------ Using alias() method
330+
.serializer("json") // <------ Using snapshot.properties
306331
.toMatchSnapshot();
307332
}
308333

@@ -388,7 +413,6 @@ Comparators follow the same resolution order as Serializers
388413
1. method
389414
1. class
390415
1. snapshot.properties
391-
1. global
392416

393417
### Example: JsonObjectComparator
394418
The default comparator may be too strict for certain types of data.

Diff for: build.gradle

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ subprojects { subproject ->
2323
shadowJar {
2424
classifier = ''
2525
relocate 'org.assertj', 'shadow.org.assertj'
26-
relocate 'org.apache.commons', 'shadow.org.apache.commons'
2726
}
2827

2928
dependencies {

Diff for: java-snapshot-testing-core/build.gradle

-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ dependencies {
99
compileOnly 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3'
1010

1111
implementation 'org.assertj:assertj-core:3.11.1'
12-
implementation 'org.apache.commons:commons-lang3:3.8.1'
1312
implementation 'org.opentest4j:opentest4j:1.1.1'
1413

1514
compileOnly 'org.slf4j:slf4j-api:2.0.0-alpha0'
@@ -21,12 +20,6 @@ dependencies {
2120
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.3.2'
2221
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.3.2'
2322
testImplementation group: 'commons-io', name: 'commons-io', version: '2.6'
24-
25-
// Required java-snapshot-testing peer dependencies
26-
testImplementation 'com.fasterxml.jackson.core:jackson-core:2.11.3'
27-
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3'
28-
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.3'
29-
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3'
3023
}
3124

3225
test { useJUnitPlatform() }

Diff for: java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/PropertyResolvingSnapshotConfig.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import au.com.origin.snapshots.comparators.SnapshotComparator;
44
import au.com.origin.snapshots.reporters.SnapshotReporter;
55
import au.com.origin.snapshots.serializers.SnapshotSerializer;
6-
import org.apache.commons.lang3.StringUtils;
76

87
import java.util.List;
98

@@ -37,6 +36,6 @@ public List<SnapshotReporter> getReporters() {
3736
@Override
3837
public boolean isCI() {
3938
String envVariable = SnapshotProperties.getOrThrow("ci-env-var");
40-
return StringUtils.isNotEmpty(System.getenv(envVariable));
39+
return System.getenv(envVariable) != null;
4140
}
4241
}

Diff for: java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Snapshot.java

+22-31
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
import au.com.origin.snapshots.comparators.SnapshotComparator;
44
import au.com.origin.snapshots.exceptions.SnapshotMatchException;
55
import au.com.origin.snapshots.reporters.SnapshotReporter;
6-
import au.com.origin.snapshots.serializers.DeterministicJacksonSnapshotSerializer;
7-
import au.com.origin.snapshots.serializers.JacksonSnapshotSerializer;
86
import au.com.origin.snapshots.serializers.SnapshotSerializer;
9-
import au.com.origin.snapshots.serializers.ToStringSnapshotSerializer;
10-
import lombok.*;
7+
import lombok.AccessLevel;
8+
import lombok.AllArgsConstructor;
9+
import lombok.SneakyThrows;
10+
import lombok.With;
1111
import lombok.extern.slf4j.Slf4j;
12-
import org.apache.commons.lang3.StringUtils;
1312

1413
import java.lang.reflect.Method;
1514
import java.util.*;
@@ -76,6 +75,17 @@ public Snapshot serializer(SnapshotSerializer serializer) {
7675
return this;
7776
}
7877

78+
/**
79+
* Apply a custom serializer for this snapshot
80+
*
81+
* @param name - the {name} attribute serializer.{name} from snapshot.properties
82+
* @return Snapshot
83+
*/
84+
public Snapshot serializer(String name) {
85+
this.snapshotSerializer = SnapshotProperties.getInstance("serializer." + name);
86+
return this;
87+
}
88+
7989
/**
8090
* Apply a custom comparator for this snapshot
8191
*
@@ -100,31 +110,12 @@ public Snapshot reporters(SnapshotReporter... reporters) {
100110
}
101111

102112
/**
103-
* Alias for serializer(new ToStringSerializer())
104-
* @return Snapshot
105-
*/
106-
public Snapshot string() {
107-
return serializer(new ToStringSnapshotSerializer());
108-
}
109-
110-
/**
111-
* Alias for serializer(new JacksonSnapshotSerializer())
112-
* @return Snapshot
113-
*/
114-
public Snapshot json() {
115-
return serializer(new JacksonSnapshotSerializer());
116-
}
117-
118-
/**
119-
* Alias for serializer(new DeterministicJacksonSnapshotSerializer())
120-
* @return Snapshot
121-
*/
122-
public Snapshot orderedJson() {
123-
return serializer(new DeterministicJacksonSnapshotSerializer());
124-
}
125-
126-
/**
127-
* Apply a custom serializer for this snapshot
113+
* Apply a custom serializer for this snapshot.
114+
* @see au.com.origin.snapshots.serializers.SnapshotSerializer
115+
*
116+
* Example implementations
117+
* @see au.com.origin.snapshots.serializers.ToStringSnapshotSerializer
118+
* @see au.com.origin.snapshots.serializers.Base64SnapshotSerializer
128119
*
129120
* @param serializer your custom serializer
130121
* @return this
@@ -212,7 +203,7 @@ private String takeSnapshot() {
212203
}
213204

214205
String getSnapshotName() {
215-
String scenarioFormat = StringUtils.isBlank(scenario) ? "" : "[" + scenario + "]";
206+
String scenarioFormat = scenario == null ? "" : "[" + scenario + "]";
216207
return testClass.getName() + "." + testMethod.getName() + scenarioFormat + "=";
217208
}
218209
}

Diff for: java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfig.java

-16
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,6 @@
1818
public interface SnapshotConfig {
1919
String JVM_UPDATE_SNAPSHOTS_PARAMETER = "updateSnapshot";
2020

21-
/**
22-
* @deprecated Use getOutputDir() instead
23-
*/
24-
@Deprecated
25-
default String getTestDir() {
26-
return getOutputDir();
27-
}
28-
2921
/**
3022
* The base directory where files get written (excluding package directories)
3123
* default: "src/test/java"
@@ -36,14 +28,6 @@ default String getTestDir() {
3628
*/
3729
String getOutputDir();
3830

39-
/**
40-
* @deprecated - use getSnapshotDir() instead
41-
*/
42-
@Deprecated
43-
default String getSnapshotFolder() {
44-
return getSnapshotDir();
45-
}
46-
4731
/**
4832
* Subdirectory to store snapshots in
4933
*

Diff for: java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotFile.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@
33
import lombok.Getter;
44
import lombok.SneakyThrows;
55
import lombok.extern.slf4j.Slf4j;
6-
import org.apache.commons.lang3.StringUtils;
76

87
import java.io.*;
9-
import java.nio.file.*;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
import java.nio.file.Paths;
11+
import java.nio.file.StandardOpenOption;
1012
import java.util.Set;
1113
import java.util.TreeSet;
1214
import java.util.function.BiFunction;
1315
import java.util.stream.Collectors;
1416
import java.util.stream.Stream;
1517

1618
@Slf4j
17-
class SnapshotFile {
19+
public class SnapshotFile {
1820

19-
private static final String SPLIT_STRING = "\n\n\n";
21+
public static final String SPLIT_STRING = "\n\n\n";
2022

2123
private final String fileName;
2224
private final Class<?> testClass;
@@ -46,7 +48,7 @@ private String getDebugFilename() {
4648
}
4749

4850
String fileText = fileContent.toString();
49-
if (StringUtils.isNotBlank(fileText)) {
51+
if (!"".equals(fileText.trim())) {
5052
rawSnapshots =
5153
Stream.of(fileContent.toString().split(SPLIT_STRING))
5254
.map(String::trim)
@@ -104,7 +106,7 @@ public void push(String snapshot) {
104106
File file = createFileIfNotExists();
105107

106108
try (FileOutputStream fileStream = new FileOutputStream(file, false)) {
107-
byte[] myBytes = StringUtils.join(rawSnapshots, SPLIT_STRING).getBytes();
109+
byte[] myBytes = String.join(SPLIT_STRING, rawSnapshots).getBytes();
108110
fileStream.write(myBytes);
109111
} catch (IOException e) {
110112
e.printStackTrace();

Diff for: java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotMatcher.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static void start(SnapshotConfig frameworkSnapshotConfig, boolean failOnO
4343
String testFilename = testClass.getName().replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + ".snap";
4444

4545
File fileUnderTest = new File(testFilename);
46-
File snapshotDir = new File(fileUnderTest.getParentFile(), snapshotConfig.getSnapshotFolder());
46+
File snapshotDir = new File(fileUnderTest.getParentFile(), snapshotConfig.getSnapshotDir());
4747

4848
// Support legacy trailing space syntax
4949
String testSrcDir = snapshotConfig.getOutputDir();

0 commit comments

Comments
 (0)