1

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.

florin
  • 719
  • 12
  • 31

1 Answers1

0

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.

Warren Nocos
  • 1,222
  • 1
  • 14
  • 29
  • Assuming that the producers produce with qualifier `@Produces @PostgresQualifier public Datasource producePostgres()` and `@Produces @H2Qualifier public Datasource produceH2()`. What type does the parameter has if I want to have constructor injection? They don't implement the same interface. For example this constructor: `@Inject public MyClass(@PostgresQualifier/@H2Qualifier Datasource ds){.....}`. – florin Sep 12 '20 at 15:06
  • Why would you have to do that? In the solution I presented, the container would produce the test data-source only when the producer is activated in the CDI descriptor file, and that's only when running tests after replacing the file. – Warren Nocos Sep 12 '20 at 16:37
  • Yes, I agree with you. In my opinion, the solution you provided is best suited for integration test. Still I don't see it applicable for unit testing. In some not so complex test scenarios I prefer to mock the collaborator. If something near what I asked in my previous comment is possible, then you can do both unit testing with mocks and integration test. – florin Sep 12 '20 at 17:52
  • If I were you, I wouldn't be creating unit tests using Arquillian. Unit tests are supposedly for testing individual components or functions, thus should be doable by purely mocking dependencies to easily lay given conditions to expect correct results. Arquillian is best suited for integration and functional testing. That being said, I believe the answer I presented is correct and should suffice your requirements. – Warren Nocos Sep 12 '20 at 21:32
  • When asking the type to expect, are you referring to the runtime type of the data-source the container injects? If so, why would you need to know? Didn't you use JPA/Hibernate? Didn't you use Wildfly/JBoss to configure the persistence context? Why does the app still need the data-source in the first place? If I were you, I would have entrusted every data-source or JPA-related stuff to the application server. – Warren Nocos Sep 12 '20 at 21:44
  • If this was because you have to do the tests, then I would strongly suggest rethinking many times because this is, I would say, too much for such requirement. Whatever the reason, I really think the solution above answers your question. – Warren Nocos Sep 12 '20 at 21:50
  • I don't want to use arquillian to do unit test just integration test. Still I want to test the same class both with unit test and integration test. For example: unit tests for simple sql queries and IT for complex sql queries. I don't use jpa/hibernate just plain jdbc – florin Sep 13 '20 at 05:31