BBL - @InjectResources - Adelean

github.com/hosuaby/inject-resources

Importer le contenu d'une ressource en Java est plus compliqué que ça ne devrais être.

Lécture d'une ressource (Java pure)

String resourcePath = "com/adelean/junit/jupiter/resource.txt";
ClassLoader classLoader = getClass().getClassLoader();

StringBuilder textBuilder = new StringBuilder();

try (InputStream resourceAsStream = classLoader.getResourceAsStream(resourcePath);
     InputStreamReader streamReader = new InputStreamReader(resourceAsStream);
     BufferedReader bufferedReader = new BufferedReader(streamReader)) {
    int c = 0;
    while ((c = bufferedReader.read()) != -1) {
        textBuilder.append((char) c);
    }
} catch (IOException ioException) {
    // handle exception
}

String resourceContent = textBuilder.toString();
// resourceContent == "The quick brown fox jumps over the lazy dog."

Lécture d'une ressource (Guava)

URL url = Resources.getResource("com/adelean/junit/jupiter/resource.txt");
try {
    String resourceContent = Resources.toString(url, StandardCharsets.UTF_8);
} catch (IOException ioException) {
    // handle exception
}

Vous ne faitez pas ça, n'est ce pas ?

try {
    import java.util.ArrayList;
} catch (IOException ioException) {
    // handle exception
}

Peut-on faire plus simple ?

Avec @InjectResources

Contenu de /com/adelean/junit/jupiter/resource.txt:

The quick brown fox jumps over the lazy dog.
@TestWithResources  // <-- ajouter l'extention
class InjectTextResourcesTests {

    @GivenTextResource("/com/adelean/junit/jupiter/resource.txt")
    String resourceContent;   // <-- injecter le contenu de la resource

    @Test
    public void testInjectTextIntoStringInstanceField() {
        assertThat(resourceContent)
                .isEqualTo("The quick brown fox jumps over the lazy dog.");
    }
}

Contenu de /com/adelean/junit/jupiter/fibonacci.bin (binaire):

1 1 2 3 5 8 13 21 34 55 89
@TestWithResources
class InjectBinaryResourcesTests {

    @GivenBinaryResource("/com/adelean/junit/jupiter/fibonacci.bin")
    byte[] fibonacci;

    @Test
    public void testInjectBinaryContentIntoByteArrayInstanceField() {
        assertThat(fibonacci)
                .contains(1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89);
    }
}

Contenu de /com/adelean/junit/jupiter/db.properties:

db.user=hosuaby
db.password=password
db.url=localhost
@TestWithResources
class InjectPropertiesResourcesTests {

    @GivenPropertiesResource("/com/adelean/junit/jupiter/db.properties")
    Properties dbProperties;

    @Test
    public void testInjectTextIntoStringInstanceField() {
        assertThat(dbProperties)
                .containsEntry("db.user", "hosuaby")
                .containsEntry("db.password", "password")
                .containsEntry("db.url", "localhost");
    }
}
Injecter contenu JSON avec Jackson
@TestWithResources
class TestsWithJackson {

    @WithJacksonMapper
    ObjectMapper objectMapper = new ObjectMapper()
            .registerModule(new JavaTimeModule());

    /* JSON */
    @GivenJsonResource("/com/adelean/junit/jupiter/sponge-bob.json")
    Map< String, Object > jsonAsMap;

    @GivenJsonResource("/com/adelean/junit/jupiter/sponge-bob.json")
    JsonNode jsonNode;

    @GivenJsonResource("/com/adelean/junit/jupiter/sponge-bob.json")
    Person spongeBob;

    /* JSONL */
    @GivenJsonLinesResource("/com/adelean/junit/jupiter/logs.jsonl")
    Log[] logsAsArray;

    @GivenJsonLinesResource("/com/adelean/junit/jupiter/logs.jsonl")
    Collection< Log > logsAsCollection;
}
Example avec un test de A2
@TestWithResources
class CatalogConfigTest {

    @WithJacksonMapper
    ObjectMapper objectMapper = JacksonUtils.objectMapper();
    
    @Test
    void testGetUsedGlobalSynonyms(
            @GivenJsonResource("com/adelean/a2/model/config/v2_frontal_648.config.json")
            CatalogConfig catalogConfig) {
        SynonymDictionary dictionary = catalogConfig.getAllSynonyms();
        
        assertTrue(dictionary.areSynonyms("rasage", "raser"));
        assertTrue(dictionary.areSynonyms("raser", "rasage"));
    }
}
Parseur partagé par plusiers classes des tests (héritage)
abstract class SuperClassWithParser {

    @WithJacksonMapper
    ObjectMapper objectMapper = new ObjectMapper()
            .registerModule(new JavaTimeModule());
}

@TestWithResources
class TestsSubclass1 extends SuperClassWithParser {

    @GivenJsonLinesResource(from = "/com/adelean/junit/jupiter/logs.jsonl")
    Collection< Log > logsAsCollection;
}

@TestWithResources
class TestsSubclass2 extends SuperClassWithParser {

    @GivenJsonResource("com/adelean/a2/model/config/v2_frontal_648.config.json")
    CatalogConfig catalog648Config;
}
Parseur partagé par plusiers classes des tests (Tests Advice)
@TestsAdvice
public final class GlobalObjectMapperProvider {

    @WithJacksonMapper
    public ObjectMapper globalObjectMapper() {
        return JacksonUtils.objectMapper();
    }
}
Parseurs nommés
@TestWithResources
class TestsWithNamedParser {

    @WithJacksonMapper("custom-mapper")
    ObjectMapper objectMapper = new ObjectMapper()
            .registerModule(new JavaTimeModule());
    
    @GivenJsonLinesResource(
        from = "/com/adelean/junit/jupiter/logs.jsonl",
        jacksonMapper = "custom-mapper")
    Collection< Log > logsAsCollection;
}
Parsing des properties dans POJO avec jackson-dataformat-properties
class JavaDslTests {
    JavaPropsSchema SCHEMA = JavaPropsSchema
            .emptySchema()
            .withoutPathSeparator();
    ObjectReader READER = new JavaPropsMapper()
            .readerFor(DbConnection.class)
            .with(SCHEMA);
    String PATH_PREFIX = "/com/adelean/junit/jupiter";
    
    static class DbConnection {
        @JsonProperty("db.user") String user;
        @JsonProperty("db.password") String password;
        @JsonProperty("db.url") String url;
    }
    
    @Test
    public void testResourceAsStream() {
        // @InjectResources Java DSL
        var dbConnection = resource()
                .withPath(PATH_PREFIX, "db.properties")
                .asInputStream()
                .parseChecked(READER::readValue);

        assertThat(dbConnection)
                .isNotNull()
                .hasFieldOrPropertyWithValue("user", "hosuaby")
                .hasFieldOrPropertyWithValue("password", "password")
                .hasFieldOrPropertyWithValue("url", "localhost");
    }
}

A venir:

La fin :)

(Merci pour votre attention!)

P.S. N'oubliez pas à visiter:

github.com/hosuaby/inject-resources