簡體   English   中英

使用Mockito模擬Spring的LocalContainerEntityManagerFactoryBean方法?

[英]Mock spring's LocalContainerEntityManagerFactoryBean method using Mockito?

我試圖為下面的代碼編寫單元測試用例,並試圖模擬EntityManager的實現。 我無法這樣做,並且在測試類中得到了空的實體管理器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();

當將此稱為輸出時,我應該返回一個列表,因此我需要模擬整個方法。 請幫忙 !

首先,應該使用@Mock而不是@InjectMocks ,並將@InjectMocks放在要進行單元測試的類上。

但是,您甚至考慮模擬LocalContainterEntityManagerFactoryBean的事實也表明您的代碼存在缺陷。 您不應在代碼中使用LCEMFB 僅用於配置。 它是一個創建EntityManagerFactoryFactoryBean ,因此實際上您應該將EntityManagerFactory注入應該FactoryBean的代碼中。

不用連接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保持打開狀態。

因此,不要注入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章節中進行了說明。

讓我擔心的另一件事是您正在使用String並將其解析為查詢。 這是潛在的危險,並且是SQL注入攻擊的原因。 而不是自己進行格式化,您應該讓它由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形式)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM