JMockit Deencapsulation setField不会持久化

时间:2017-07-17 09:57:34

标签: java jpa derby jmockit

我正在编写JPA层和数据库之间的集成测试,以检查我写的SQL是否正确。真正的数据库是Oracle,不幸的是,由于我的控制,我的测试数据库必须是Derby,因此自然存在一些差异。例如,我的JPA类具有以下SQL字符串常量

private static final String QUERY = "Select * from Users where regexp_like(user_code, '^SS(B)?N')";

因为Derby不支持regexp_like我正在使用JMockits Deencapsulation.setField来动态更改SQL。例如

@Test
public void testMyDaoFind() {
    new Expectations() {
        {
            Deencapsulation.setField(MyClass.class, "QUERY", "Select * from Users");
        }
    };

    dao.findUsers();
}

现在忽略了这不是一个好测试的事实,因为它没有测试将在真实数据库上运行的实际查询(这纯粹是为了满足我对正在发生的事情的好奇心),我得到了一个Eclipselink / Derby抱怨regexp_like的SQL异常错误不会被识别为函数或过程。

如果我在尝试获取结果列表的DAO中的行上放置一个断点,我可以从新手表中看到

  1. JMockit已正确替换查询

  2. getResultList()返回我期待看到的数据

  3. 但是,如果我让测试一直运行,那么我得到了前面提到的异常?!

1 个答案:

答案 0 :(得分:3)

Java中的字符串不会按照您的思维方式处理。 Java源代码编译器将包含字符串文字的字段中的读取替换为固定的"地址"存储字符串的位置(在类'常量池中);在运行时不再读取该字段。因此,即使JMockit替换了字段中存储的字符串引用,也没有区别,因为使用该字段的客户端代码没有看到该引用。

(顺便说一句,为什么测试将Deencapsulatin.setField的调用置于期望区块内?这些块仅用于记录预期......)

总而言之,没有办法实现你想要的目标。相反,要么使用Oracle数据库进行集成测试,要么使所有SQL代码都可移植,避免使用特定于RDBMS的函数,例如regexp_like