模拟EntityManager [英] Mocking EntityManager

查看:122
本文介绍了模拟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不为null(其他参数REPLICATION_DOMAIN, 实体类中的SOURCE_NODE_INDEX,NODE_CHANGE_NUMDER不为null),而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. 想象一下模拟第三方库的代码.在对第三个库进行特定升级之后,逻辑可能会有所变化,但是测试套件可以很好地执行,因为它是模拟的.所以以后,认为一切都很好,构建墙毕竟是绿色的,已经部署了软件,然后... Boom
  2. 这可能表明当前的设计与该第三方库的耦合不够充分.
  3. 另一个问题是,第三方lib可能很复杂,需要很多模拟才能正常工作.这就导致了过度指定的测试和复杂的测试装置,这本身就损害了紧凑和可读的目标.或者是由于模拟外部系统的复杂性而导致测试无法涵盖足够的代码.
  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.

您没有控件的

模拟类型可以视为( mocking )反模式.尽管EntityManager几乎是标准,但人们不应该考虑在即将发布的JDK/JSR版本中不会有任何行为更改(在API的其他部分已经发生了很多次,请看一下JDK发行说明).再加上真正的实现可能在行为上有微妙之处,很难被嘲笑,测试可能是绿色的,但生产中的雄猫却火上浇油(真实的故事).

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).

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

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天全站免登陆