模拟 EntityManager [英] Mocking EntityManager

查看:15
本文介绍了模拟 EntityManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在模拟 EntityManager 时遇到了 NPE,下面是我的代码,

I am getting NPE while mocking EntityManager, below is my code,

@Stateless
public class NodeChangeDeltaQueryBean implements NodeChangeDeltaQueryLocal {

    @PersistenceContext
    private EntityManager em;
    @Override
    public String findIdByNaturalKey(final String replicationDomain, final int sourceNodeIndex,
                                     final int nodeChangeNumber) {
        List<String> result =
            NodeChangeDelta.findIdByNaturalKey(this.em, replicationDomain, sourceNodeIndex,
                nodeChangeNumber).getResultList();
        return result.isEmpty() ? null : result.get(0);
    }
}

我的实体类

@Entity
public class NodeChangeDelta implements Serializable, Cloneable, GeneratedEntity, KeyedEntity<String> {

public static TypedQuery<String> findIdByNaturalKey(final EntityManager em, final String replicationDomain, final int sourceNodeIndex, final int nodeChangeNumber) {
        return em.createNamedQuery("NodeChangeDelta.findIdByNaturalKey", String.class)
            .setParameter("replicationDomain", replicationDomain)
            .setParameter("sourceNodeIndex", sourceNodeIndex)
            .setParameter("nodeChangeNumber", nodeChangeNumber);
    }
}

我的测试课

@RunWith(MockitoJUnitRunner.class)
public class NodeChangeDeltaQueryBeanTest {

    @InjectMocks
    NodeChangeDeltaQueryBean nodeChangeDeltaQueryBean;

    @Mock
    EntityManager em;

@Test
    public void testFindIdByNaturalKey() {
        this.addNodeChangeDelta();
        this.nodeChangeDeltaQueryBean.findIdByNaturalKey(this.REPLICATION_DOMAIN,
            this.SOURCE_NODE_INDEX, this.NODE_CHANGE_NUMDER);
    }
}

虽然调试 em 不为空(还有其他参数 REPLICATION_DOMAIN,SOURCE_NODE_INDEX, NODE_CHANGE_NUMDER not null) 在 Entity 类中,而 em.createNamedQuery("NodeChangeDelta.findIdByNaturalKey", String.class) 为 null.

While debugging em is not null (also other arguments REPLICATION_DOMAIN, SOURCE_NODE_INDEX, NODE_CHANGE_NUMDER not null) in Entity class, whereas em.createNamedQuery("NodeChangeDelta.findIdByNaturalKey", String.class) is null.

推荐答案

在 mockito wiki 上:不要模拟你不拥有的类型!

On the mockito wiki : Don't mock types you don't own !

这不是一条硬线,但越过这条线可能会产生影响!(很可能会.)

  1. 想象一下模拟第三方库的代码.在对第三个库进行特定升级后,逻辑可能会发生一些变化,但测试套件会执行得很好,因为它是模拟的.所以后来,认为一切都很好,毕竟构建墙是绿色的,软件已经部署并且...... 繁荣
  2. 这可能表明当前设计与此第三方库的分离程度不够.
  3. 另一个问题是第三方库可能很复杂,甚至需要大量模拟才能正常工作.这会导致过度指定的测试和复杂的固定装置,这本身就会损害紧凑和可读的目标.或者因为模拟外部系统的复杂性而没有足够覆盖代码的测试.
  1. Imagine code that mocks a third party lib. After a particular upgrade of a third library, the logic might change a bit, but the test suite will execute just fine, because it's mocked. So later on, thinking everything is good to go, the build-wall is green after all, the software is deployed and... Boom
  2. It may be a sign that the current design is not decoupled enough from this third party library.
  3. Also another issue is that the third party lib might be complex and require a lot of mocks to even work properly. That leads to overly specified tests and complex fixtures, which in itself compromises the compact and readable goal. Or to tests which do not cover the code enough, because of the complexity to mock the external system.

相反,最常见的方法是围绕外部库/系统创建包装器,但应注意抽象泄漏的风险,即过多的低级 API、概念或异常超出了包装器的边界.为了验证与第三方库的集成,编写集成测试,并使其尽可能紧凑和可读.

Instead, the most common way is to create wrappers around the external lib/system, though one should be aware of the risk of abstraction leakage, where too much low level API, concepts or exceptions, goes beyond the boundary of the wrapper. In order to verify integration with the third party library, write integration tests, and make them as compact and readable as possible as well.

您没有控制权的 Mock 类型可以被视为 (mocking) 反模式.虽然 EntityManager 几乎是标准,但不应考虑在即将发布的 JDK/JSR 版本中不会有任何行为变化(它已经在其他部分发生过很多次了)API,看 JDK 发行说明).此外,真正的实现可能在其行为中存在难以被嘲笑的微妙之处,测试可能是绿色的,但生产中的 tomcat 却着火了(真实故事).

Mock type that you don't have the control can be considered a (mocking) anti-pattern. While EntityManager is pretty much standard, one should not consider there won't be any behavior change in upcoming JDK / JSR releases (it already happened numerous time in other part of the API, just look at the JDK release notes). Plus the real implementations may have subtleties in their behavior that can hardly be mocked, tests may be green but the production tomcats are on fire (true story).

我的观点是,如果代码需要模拟我不拥有的类型,则设计应该尽快改变,这样我、我的同事或该代码的未来维护者就不会陷入这些陷阱.

My point is that if the code needs to mock a type I don't own, the design should change asap so I, my colleagues or future maintainers of this code won't fall in these traps.

还有其他博客条目的 wiki 链接描述了他们在尝试模拟他们无法控制的类型时遇到的问题.

Also the wiki links to other blogs entries describing issues they had when they tried to mock type they didn't have control.

相反,我真的建议大家在测试与其他系统的集成时不要使用模拟.我相信对于数据库的东西,Arquillian 是最好的选择,该项目似乎非常活跃.

Instead I really advice everyone to don't use mock when testing integration with another system. I believe for database stuff, Arquillian is the thing to go, the project appears to be quite active.

改编自我的回答:https://stackoverflow.com/a/28698223/48136一个>

这篇关于模拟 EntityManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆