@TestResource
A lot of people have one or more utility methods like this:
private static String readResource(String name) {
StringBuilder sb = new StringBuilder();
try (Reader input = new InputStreamReader(MyClassTest.class.getResourceAsStream(name), StandardCharsets.UTF_8)) {
char[] buffer = new char[4096];
int len;
while ((len = input.read(buffer)) != -1) {
sb.append(buffer, 0, len);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return sb.toString();
}
Instead of having to write this boilerplate code for every project (and sometimes for multiple test classes inside the same project), annotate fields, constructor parameters or method parameters with @TestResource to inject a Java resource into the field, constructor parameter or method parameter.
Note that the resource name is relative to the class that defines the field, constructor or method. Use a leading /
to start from the root of the class path.
Injecting byte[]
The simplest form is to inject into a field, constructor parameter or method parameter of type byte[]
. Just annotate the injection target with @TestResource
:
@Test
void testWithResource(@TestResource("my-file.bin") byte[] myFile) {
// use myFile as needed
}
Injecting String, CharSequence or StringBuilder
Injecting into a field, constructor parameter or method parameter of type String
, CharSequence
or StringBuilder
works the same as for byte[]
. In addition, the encoding and line separators can be specified.
Specifying the encoding
By default, resources are loaded as UTF-8. In some cases this may not be the correct encoding. There are two ways to specify the encoding to use:
- Use @Encoding. This annotation can be placed on the injection target, or any enclosing element. For instance, for a method parameter, it can be placed on the method parameter itself, the method, or the class that defines the method. If that class is nested inside another class, that class is also checked, up to the root class.
- Use the
com.github.robtimus.junit.support.extension.testresource.encoding
JUnit configuration parameter to define the default encoding, in case no@Encoding
annotation is found. This configuration parameter can have the following values:DEFAULT
forCharset.defaultCharset()
SYSTEM
for system propertyfile.encoding
; if this system property is not set, an error will be thrownNATIVE
for system propertynative.encoding
, which is available since Java 17; if this system property is not set, an error will be thrown- The name of a charset for that specific charset
For instance:
@Test
void testWithResource(@TestResource("my-file.txt") @Encoding("ISO-8859-1") String myFile) {
// myFile has been loaded using the ISO-8859-1 charset
}
Specifying the line separator
By default, the resource is loaded as-is. This may cause issues when tests are run on platforms with different line separators, for example Linux and Windows. There are two ways to specify the line separator to use:
- Use @EOL. This annotation can be placed on the injection target, or any enclosing element. For instance, for a method parameter, it can be placed on the method parameter itself, the method, or the class that defines the method. If that class is nested inside another class, that class is also checked, up to the root class.
- Use the
com.github.robtimus.junit.support.extension.testresource.lineSeparator
JUnit configuration parameter to define the default line separator, in case no@EOL
annotation is found. This configuration parameter can have the following values:LF
for\n
CR
for\r
CRLF
for\r\n
SYSTEM
forSystem.lineSeparator()
ORIGINAL
for line separators from the original file; this is the default settingNONE
for no line separators- A literal value for that specific line separator
For instance:
@Test
void testWithResource(@TestResource("my-file.txt") @EOL(EOL.LF) String myFile) {
// myFile uses \n as line separator, no matter the platform
}
Custom resource-to-object conversion
Combine @TestResource
with @LoadWith to provide your own resource-to-object conversion. For instance:
@Test
void testWithResource(@TestResource("person.xml") @LoadWith("xmlToPerson") Person person) {
// use person as needed
}
Person xmlToPerson(Reader reader) throws IOException {
// perform conversion, e.g. using JAXB
}
The method reference in the annotation can come in the following formats:
Format | Description |
---|---|
<methodName> |
A method in the test class itself |
<methodName(<parameterTypes>) |
A method in the test class itself, with the given comma separated parameter types |
<fullyQualifiedClassName>#<methodName> |
A method in the given class |
<fullyQualifiedClassName>#<methodName>(<parameterTypes>) |
A method in the given class, with the given comma separated parameter types |
The parameter types can be one of the following combination; if they are not given, the method lookup will be performed in this order:
java.io.Reader
,com.github.robtimus.junit.support.extension.InjectionTarget
java.io.Reader
,java.lang.Class
java.io.Reader
java.io.InputStream
,com.github.robtimus.junit.support.extension.InjectionTarget
java.io.InputStream
,java.lang.Class
java.io.InputStream
The InjectionTarget or Class
arguments represents the target or target type respectively, and can be used for dynamic conversion methods. For instance:
@Test
void testWithResource(@TestResource("person.xml") @LoadWith("xmlToObject") Person person) {
// use person as needed
}
@Test
void testWithResource(@TestResource("address.xml") @LoadWith("xmlToObject") Address address) {
// use address as needed
}
<T> T xmlToObject(Reader reader, Class<T> type) throws IOException {
// perform conversion, e.g. using JAXB
}
Specifying the encoding
When using a method that takes a Reader
, the encoding can be specified in the same way as for String
, CharSequence
or StringBuilder
, using @Encoding
or the com.github.robtimus.junit.support.extension.testresource.encoding
JUnit configuration parameter. It's not allowed to use @Encoding
for methods that take an InputStream
.
Injecting lines
Two specialized versions of @LoadWith
are provided for lines, @AsLines and @AsLinesArray:
// inject as a static field
@TestResource("test.properties")
@AsLines
private static List<String> testLines;
@TestResource("test.properties")
@AsLinesArray
private static String[] testLinesArray;
Injecting Properties
A specialized version of @LoadWith
is provided for Properties
objects, @AsProperties:
// inject as a static field
@TestResource("test.properties")
@AsProperties
private static Properties testProperties;