Mocking EntityManager



我在嘲笑EntityManager时得到了NPE,下面是我的代码

@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不为null),而em.createNamedQuery("NodeChangeDelta.findIdByNaturalKey",String.class)为null。

在mockito wiki上:不要嘲笑你不拥有的类型!

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

  1. 想象一下模拟第三方lib的代码。在对第三个库进行特定升级后,逻辑可能会发生一些变化,但测试套件会执行得很好,因为它被嘲笑了。所以后来,认为一切都很好,建造墙毕竟是绿色的,软件已经部署好了吊杆
  2. 这可能是一个迹象,表明当前的设计与这个第三方库的解耦程度不够
  3. 另一个问题是,第三方lib可能很复杂,甚至需要大量mock才能正常工作。这导致了过度指定的测试和复杂的固定装置,这本身就损害了紧凑和可读的目标。或者由于模拟外部系统的复杂性,测试没有充分覆盖代码

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

没有控件的Mock类型可以被视为(mocking)反模式。虽然EntityManager在很大程度上是标准,但不应认为在即将发布的JDK/JSR版本中不会有任何行为变化(在API的其他部分中已经发生过多次,只需查看JDK的发行说明即可)。此外,真正的实现可能在其行为中有一些微妙之处,这些细微之处很难被嘲笑,测试可能是绿色的,但生产中的tomcat却很火(真实的故事)。

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

此外,维基链接到其他博客条目,描述他们在试图模仿他们无法控制的类型时遇到的问题。

相反,我真的建议大家在测试与另一个系统的集成时不要使用mock。我相信对于数据库的东西,Arquillian是最好的选择,这个项目看起来相当活跃。


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

在Mockito中,未显式配置的mock上的任何方法调用都将返回null。因此,在findIdByNaturalKey中,em.createNamedQuery返回null,因此在setParameter上返回NPE。您需要将其配置为RETURN_LOCKS。

另外,我不确定@InjectMocks是否支持@PersistenceContext。如果没有,则em可能为空。如果是,请告诉我,以上就是您的问题。

相关内容

  • 没有找到相关文章

最新更新