我在嘲笑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上:不要嘲笑你不拥有的类型!
这不是一条硬线,但越过这条线可能会产生影响!(很可能会。)
- 想象一下模拟第三方lib的代码。在对第三个库进行特定升级后,逻辑可能会发生一些变化,但测试套件会执行得很好,因为它被嘲笑了。所以后来,认为一切都很好,建造墙毕竟是绿色的,软件已经部署好了吊杆
- 这可能是一个迹象,表明当前的设计与这个第三方库的解耦程度不够
- 另一个问题是,第三方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
可能为空。如果是,请告诉我,以上就是您的问题。