我正在尝试为下面的代码编写单元测试用例,并且我正在尝试模拟EntityManager实现。我无法这样做,我在我的测试类中获得了null实体管理器bean。
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
我写的模拟测试代码如下:
@InjectMocks
private LocalContainerEntityManagerFactoryBean emMock = new LocalContainerEntityManagerFactoryBean();
...
Mockito.when(localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager()).thenReturn();
当我将其作为输出调用时,我应该返回一个列表所以我需要整个方法进行模拟。请帮忙!
答案 0 :(得分:2)
首先关闭所有内容而不是@InjectMocks
,您应该使用@Mock
并将@InjectMocks
放在您尝试进行单元测试的类上。
然而,您甚至考虑嘲笑LocalContainterEntityManagerFactoryBean
这一事实表明您的代码存在缺陷。你不应该在代码中使用LCEMFB
。它仅用于配置。这是一个FactoryBean
创建一个EntityManagerFactory
,所以实际上你应该在代码中注入EntityManagerFactory
,你应该嘲笑它。
而不是连接LCEMFB
,而是使用普通EMF
并通过使用@PersistenceUnit
注释字段来获取实例。
@PersistenceUnit
private EntityManagerFactory emf;
然后你的方法也更清洁了
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
然而,您实际应该做的是注入EntityManager
并且不要尝试自己创建一个(您的代码仍然存在缺陷,因为您还没有关闭事务,也没有创建{{} 1}}反过来最终会导致您无法连接到您的数据库,因为基础EntityManager
也会保持打开状态。
因此,不是注入Connection
或LCEMFB
而是使用普通EMF
,而是让Spring为您管理。要让spring管理交易,请确保您的配置中有EntityManager
或@EnableTransactionManagement
,否则它将无法正常运行。
<tx:annotation-driven />
现在你的方法真正关注它应该做什么,从数据库中获取数据。
@PersistenceContext
private EntityManager em;
现在,在您的测试中,您只需要模拟@Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
return em.createNativeQuery(query).getResultList();
}
。
所有这些也在Spring参考指南的ORM chapter中进行了解释。
让我担心的另一件事是你正在使用String并解析它以用作查询。这有潜在危险,是SQL injection attacks的原因。您应该让它由Hibernate或JDBC处理,而不是自己进行格式化。
EntityManager
上面的代码假设@Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
Query q = em.createNativeQuery(query);
q.setParameter("siteId", siteId)
.setParameter("startTime", startTime)
.setParameter("endTime", endTimestamp);
return q.getResultList();
}
形式的查询(或者您的SQL看起来像什么)。