Search code examples
springunit-testingspring-testbitronix

Bitronix + Spring tests + Different spring profiles


I have several tests which all extends the same root test which define the Spring test application context. One of my test use a different profile so I have annotated the child class with @ActiveProfiles("specialTestProfile"), this profile create a special mock bean which is injected in the context. I want to clear my context before and after executing this test, but I didn't find the correct way to do it. I know that the Spring test framework does some context caching and that in my case I should have two different context and it should not be necessary to reload the context but it is not working because of bitronix which generate this strange error if I don't clean the context:

    Caused by: bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named unittestdb
    at bitronix.tm.resource.jdbc.PoolingDataSource.init(PoolingDataSource.java:57)
    at sun.reflect.GeneratedMethodAccessor404.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1608)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1549)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1479)
    ... 62 more
Caused by: java.lang.IllegalArgumentException: resource with uniqueName 'unittestdb' has already been registered
    at bitronix.tm.resource.ResourceRegistrar.register(ResourceRegistrar.java:55)
    at bitronix.tm.resource.jdbc.PoolingDataSource.buildXAPool(PoolingDataSource.java:68)
at bitronix.tm.resource.jdbc.PoolingDataSource.init(PoolingDataSource.java:53)
... 68 more

Even if I reload the context for each test class (by annotating my parent class with @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS), I still get the error above at some point... do you have any idea how to solve this problem?


Solution

  • Without seeing your exact configuration for the PoolingDataSource, I cannot know exactly how to solve your issue.

    However, it appears that you can likely solve this issue by creating your PoolingDataSource with a unique name by invoking the setUniqueName() method (in an @Bean method if you're using Java config) or by setting the uniqueName property (if you're using XML config). How you generate the unique name depends on the configuration style you are using.

    If you do not set a unique name for each ApplicationContext that creates the PoolingDataSource bean, you will continue to see the exception telling you that a second pool cannot be created with the "unittestdb" name since it already exists. The reason is that the init() method in PoolingDataSource delegates to ManagementRegistrar.register() which registers an MBean under the unique name, and the same MBeanServer is used for all tests within the same JVM process (i.e., for all tests in your suite).

    Instead of generating a unique pool name per application context, another option might be to disable the use of JMX by setting the bitronix.tm.disableJmx property to false. Consult the isDisableJmx() and setDisableJmx() methods in bitronix.tm.Configuration for details.