JMockit Deencapsulation setField 不持久

JMockit Deencapsulation setField not persisting

我正在我的 JPA 层和数据库之间编写集成测试,以检查我编写的 SQL 是否正确。真正的数据库是 Oracle,不幸的是,由于我无法控制的原因,我的测试数据库必须是 Derby,所以自然会有一些差异。例如我的 JPA class 有以下 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();
}

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

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

  1. JMockit 已正确替换查询

  2. getResultList() returns 我期望看到的数据

但是,如果我让测试 运行 一直通过,那么我会得到上述异常?!

Java 中的字符串未按照您的想法处理。 Java 源代码编译器用存储字符串的固定 "address"(在 class' 常量池中)替换从保存字符串文字的字段读取;该字段在运行时不再读取。因此,即使 JMockit 替换了字段中存储的字符串引用,也没有任何区别,因为使用该字段的客户端代码看不到该引用。

(顺便说一句,为什么测试将对 Deencapsulatin.setField 的调用放在预期块内?此类块仅用于记录预期...)

归根结底,您无法实现您的目标。相反,要么使用 Oracle 数据库进行集成测试,要么使所有 SQL 代码可移植,避免 RDBMS 特定的功能,例如 regexp_like.