尽管加载了正确的应用程序上下文,JUnit仍会测试访问错误的数据库

时间:2016-06-02 14:39:21

标签: junit jooq applicationcontext

我目前对此处所看到的内容没有任何解释 - 如果您需要更多信息,请与我们联系

我有一个应用程序上下文文件

src/test/resources/applicationContext-jooq-test.xml

看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure -->

    <!-- This is needed for the @Transactional annotation -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <mvc:resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <context:component-scan base-package="com.mz.server" />

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/mz_testdb?useSSL=false" />
        <property name="username" value="root" />
        <property name="password" value="" />
    </bean>

    <!-- Configure Spring's transaction manager to use a DataSource -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- Configure jOOQ's TransactionProvider as a proxy to Spring's transaction manager -->
    <bean id="transactionProvider"
        class="com.mz.server.SpringTransactionProvider">
    </bean>

    <!-- Configure jOOQ's ConnectionProvider to use Spring's TransactionAwareDataSourceProxy,
         which can dynamically discover the transaction context -->
    <bean id="transactionAwareDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
        <constructor-arg ref="dataSource" />
    </bean>

    <bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider">
        <constructor-arg ref="transactionAwareDataSource" />
    </bean>

    <!-- Configure the DSL object, optionally overriding jOOQ Exceptions with Spring Exceptions -->
    <bean id="dslContext" class="org.jooq.impl.DefaultDSLContext">
        <constructor-arg ref="config" />
    </bean>

    <!-- Invoking an internal, package-private constructor for the example
         Implement your own Configuration for more reliable behaviour -->
    <bean class="org.jooq.impl.DefaultConfiguration" name="config">
        <property name="SQLDialect"><value type="org.jooq.SQLDialect">MYSQL</value></property>
        <property name="connectionProvider" ref="connectionProvider" />
        <property name="transactionProvider" ref="transactionProvider" />
    </bean>

</beans>

正如您所见,我明确mz_testdb定义为我的目标数据库。

对于我的JUnit测试,我有AbstractRepositoryTest除了初始化数据库并在测试开始之前将其置于有用状态之外什么都不做:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/applicationContext-jooq-test.xml")
public abstract class AbstractRepositoryTest {

    private final static Logger LOGGER = Logger.getLogger(AbstractRepositoryTest.class.getName());

    private static DSLContext ctx;

    public AbstractRepositoryTest() {

    }

    @BeforeClass
    public static void setUpDatabase() {

        LOGGER.debug("Setting up database for unit tests ..");

        @SuppressWarnings("resource")
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-jooq-test.xml");
        DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");

        FlywayDbMain flywayDbMain = new FlywayDbMain();

        boolean databaseOkay = flywayDbMain.setUpCleanDatabase(dataSource);

        AbstractRepositoryTest.ctx = (DSLContext) applicationContext.getBean("dslContext");

        org.junit.Assume.assumeTrue(databaseOkay);

    }

    protected static DSLContext getContext() {
        return AbstractRepositoryTest.ctx;
    }
}

当然,我准备了一个测试:

public class ShopRepositoryTest extends AbstractRepositoryTest {

    private final static Logger LOGGER = Logger.getLogger(ShopRepositoryTest.class.getName());

    private ShopRepository shopRepository;

    private Long shop1Id;

    private Long shop2Id;

    private final static Long LANG_GERMAN = 1L;

    private final static Long LANG_ENGLISH = 2L;

    @Before
    public void before() {

        try {

            this.shopRepository = new ShopRepository(AbstractRepositoryTest.getContext());

            LOGGER.info("Setting up database ..");

            // Shop 1

            this.shop1Id = this.shopRepository.createShop("Shop 1", 46.061785f, 16.464123f, "Europe/Vienna", LANG_GERMAN);

            this.shopRepository.addSupportedLanguage(this.shop1Id, LANG_GERMAN);
            this.shopRepository.addSupportedLanguage(this.shop1Id, LANG_ENGLISH);

            // Shop 2

            this.shop2Id = this.shopRepository.createShop("Shop 2", 46.061785f, 16.464123f, "Europe/Vienna", LANG_GERMAN);

            this.shopRepository.addSupportedLanguage(this.shop2Id, LANG_GERMAN);
            this.shopRepository.addSupportedLanguage(this.shop2Id, LANG_ENGLISH);

        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void deleteAllItemDetails() {
        // ...
    }

    @After
    public void after() {
        LOGGER.debug("All done.");
    }

}

现在,我得到的错误如下:

Caused by: java.sql.SQLSyntaxErrorException: Table 'mz_db.shop' doesn't exist
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:686)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:663)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:653)

我已经从我的代码中调试了这艘船,但我还是没有看到它。 哪里为什么我突然与我的开发人员数据库mz_db交谈?如果我逐步遍历代码,我看,我发现网址实际上是正确的:

enter image description here

事实上,有关于mz_db的讨论,但这些都在

/src/main/webapp/WEB-INF/spring/applicationContext-jooq.xml

当然,如果我创建mz_db我没有得到此异常,但所有数据都写入此表,这不是我想要的。

我很好奇我是如何设法做这样的事情的,这一定是愚蠢的,我没有看到。

这里发生了什么?

我已经尝试

  • 清理所有项目
  • 删除target/文件夹
  • 重启Eclipse

1 个答案:

答案 0 :(得分:0)

jOOQ本身并不关心您的JDBC连接URL。这只是表格不完全限定时使用的默认数据库。但是jOOQ默认完全限定具有模式名称的表(= MySQL中的数据库名称)。因此,如果从mz_db数据库生成jOOQ表并针对mz_testdb连接运行查询,则生成的SQL仍将完全限定mz_db.shop表,因为它最初生成。

有两种方法可以解决这个问题:

  1. 使用Settings.renderSchema
  2. 禁用完全限定表格
  3. 使用Settings.renderMapping配置架构映射,将mz_db重写为mz_testdb
  4. 后者也记录在这里: http://www.jooq.org/doc/latest/manual/sql-building/dsl-context/runtime-schema-mapping