2016-07-22 33 views
0

我想爲下面的代碼編寫單元測試用例,並試圖模擬EntityManager實現。我無法這樣做,並且在測試類中獲得了空實體管理器bean。使用Mockito模擬彈簧的LocalContainerEntityManagerFactoryBean方法?

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

@InjectMocks將嘗試在LocalContainerEntityManagerFactoryBean中注入它的依賴項,但是沒有定義任何其他bean,不知道要注入什麼。 –

+0

而不是模擬'LocalContainerEntityManager'修復你的代碼是正確的,這樣你就不必嘲笑它。你的代碼有缺陷。 –

回答

1

首先關閉所有而不是@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不要試圖自己創建一個(你的代碼仍然是有缺陷的,你不會關閉交易,也不會創建EntityManager,這反過來最終會導致您無法連接到您的數據庫,因爲底層的Connection也保持打開狀態。

因此,替代injec或者LCEMFBEMF改爲使用普通EntityManager,讓Spring爲您管理它。要讓Spring管理交易,請確保您的配置中有@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(); 
} 

現在在你的測試中,你應該只需要模擬EntityManager

所有這些都在Spring參考指南的ORM chapter中有解釋。

另一件讓我擔心的事情是您正在使用一個字符串並將其用作查詢。這是潛在的危險,併爲SQL injection attacks的原因。不要自己格式化,而應該讓它由Hibernate或JDBC來處理。

@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(); 
} 

上面的代碼假定在SELECT * FROM YOURTABLE WHERE siteId=:siteId and startTime >= :startTime and endTime <= :endTime形式查詢(或任何你的SQL的樣子)。