jakarta-eejava-ee-6java-ee-7jboss-arquillianjava-ee-8

How to test data source injected with @Resource


I want to create some integration tests for the following class:

public class MyDao {
    @Inject
    @Postgres
    private DataSource dataSource;

    getSomething() {
        //do something with dataSource
    }
}

I have the qualifier:

@Qualifier
@Target({ TYPE, METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
public @interface Postgres {
}

And also I have a producer:

public class PostgresDataSourceProducer {

    @Resource(mappedName = "java:jboss/PostgresDS")
    private DataSource ds;

    @Produces
    @Postgres
    DataSource postgresDataSouce() {
        return ds;
    }
}

I'm using wildfly 14. Data source was defined in the standalone.xml:

<subsystem xmlns="urn:jboss:domain:datasources:5.0">
        <datasources>
            <datasource jta="false" jndi-name="java:jboss/PostgresDS" pool-name="postgres" enabled="true" use-ccm="false">
                <connection-url>jdbc:postgresql://${production.postgres.url}</connection-url>
                <driver-class>org.postgresql.Driver</driver-class>
                <driver>postgresql-8.0-310.jdbc3.jar</driver>
                <security>
                    <user-name>${db.username}</user-name>
                    <password>${db.userpass}</password>
                </security>
                <validation>
                    <validate-on-match>false</validate-on-match>
                    <background-validation>false</background-validation>
                </validation>
                <statement>
                    <share-prepared-statements>false</share-prepared-statements>
                </statement>
            </datasource>
        </datasources>
</subsystem>

To create integration tests, I will need to change the datasource to point to my test database. How to do that?

Because it'a a legacy code, I'm reserved to switch from @Resource to @PersistenceContext.


Solution

  • There are many ways to do this, but first, define your test data-source in the subsystem (let's map it with java:jboss/H2 for the sake of the examples below).

    Via the CDI @Alternative

    Create another producer class for the test data-source and marked it as an alternative.

    Example:

    public class PostgresDataSourceProducer {
    
        @Resource(mappedName = "java:jboss/PostgresDS")
        private DataSource primary;
    
    }
    
    @Alternative
    public class H2DataSourceProducer {
    
        @Resource(mappedName = "java:jboss/H2")
        private DataSource test;
    
    }
    

    In the test resource directory, add a new CDI descriptor file specifically for tests. You may want to copy the configs from the main descriptor file to retain behaviors or avoid runtime errors.

    Example:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
           version="1.1" bean-discovery-mode="all">
        <alternatives>
             <class>path.to.your.datasource.H2DataSourceProducer</class>
        </alternatives>
    </beans>
    

    And lastly, when creating your test artifacts via Shrinkwrap, replace the CDI descriptor files for the affected modules with the one above.

    Example:

    final var services = ...;
    services.addAsManifestResource("META-INF/beans.xml", "beans.xml");
    

    Via the JPA Persistence-unit config

    You may also just scrape the data-source producer and let JPA get the correct data-source at runtime via the persistence-unit config.

    Add a new persistence.xml file in the test resource directory. Retain everything from the main persistence config except for the data-source property.

    Example:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
                 version="2.2">
        <persistence-unit name="primary">
            
            <!--<jta-data-source>java:jboss/PostgresDS</jta-data-source>-->
            <jta-data-source>java:jboss/H2</jta-data-source>
            ...
        </persistence-unit>
    </persistence>
    

    And lastly, when creating your test artifacts via Shrinkwrap, replace the main persistence config file with the one above.