2011-10-14 111 views
7

我正在做一個關於EJB 3.1單元測試的小研究。最後,我的目標是爲單元測試EJB 3.1生成一個易於使用的解決方案。單元測試EJB 3.1

  1. 我沒有大EJB實現很多知識,因此我想先得到一些經驗豐富的手(你),只是在游泳池你的想法是什麼是單元測試EJB的困難。
  2. 通過我已經完成的初步研究,我可以理解使用模擬框架進行單元測試而不是使用嵌入式容器的優點。雖然兩者都很好,但在單元測試方面,嘲諷框架還是有點高。嵌入式容器當然非常好,並且有各自的優點,但可能是單元測試的不同階段。至少在某些情況下,我仍然認爲應該有一些不足之處,可以改進這種框架。

我希望我能爲單元測試EJB做一個完整的解決方案,我可以在這個論壇上分享一次。

感謝您的支持。

回答

14

我給你的建議是不要陷入我看到的共同陷阱,那就是認爲你需要在模擬和使用嵌入式EJB容器之間進行選擇。

您可以同時使用兩者,您應該同時使用兩者,並且在難以使用的地方,您應該要求EJB容器提供更好的支持和更多功能。

當然,你會發現在OpenEJB的人真的很支持,並且很樂意添加功能來支持獲得兩全其美的好處。幾乎所有真正優秀的功能都是圍繞用戶嘗試做出非常具體的事情並發現困難的請求而創建的。

標準API的EJBContainer

package org.superbiz.stateless.basic; 

import junit.framework.TestCase; 

import javax.ejb.embeddable.EJBContainer; 

public class CalculatorTest extends TestCase { 

    private CalculatorBean calculator; 

    /** 
    * Bootstrap the Embedded EJB Container 
    * 
    * @throws Exception 
    */ 
    protected void setUp() throws Exception { 

     EJBContainer ejbContainer = EJBContainer.createEJBContainer(); 

     Object object = ejbContainer.getContext().lookup("java:global/simple-stateless/CalculatorBean"); 

     assertTrue(object instanceof CalculatorBean); 

     calculator = (CalculatorBean) object; 
    } 

完整的源here

這會掃描類路徑和加載所有豆類。

沒有掃描,更容易嘲諷方法

略有不同的方法,你在代碼中定義的一切。顯然,嘲笑更容易,因爲您可以隨時提供需要的模擬bean實現。

@RunWith(ApplicationComposer.class) 
public class MoviesTest extends TestCase { 

    @EJB 
    private Movies movies; 

    @Resource 
    private UserTransaction userTransaction; 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Module 
    public PersistenceUnit persistence() { 
     PersistenceUnit unit = new PersistenceUnit("movie-unit"); 
     unit.setJtaDataSource("movieDatabase"); 
     unit.setNonJtaDataSource("movieDatabaseUnmanaged"); 
     unit.getClazz().add(Movie.class.getName()); 
     unit.setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)"); 
     return unit; 
    } 

    @Module 
    public EjbJar beans() { 
     EjbJar ejbJar = new EjbJar("movie-beans"); 
     ejbJar.addEnterpriseBean(new StatefulBean(MoviesImpl.class)); 
     return ejbJar; 
    } 

    @Configuration 
    public Properties config() throws Exception { 
     Properties p = new Properties(); 
     p.put("movieDatabase", "new://Resource?type=DataSource"); 
     p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver"); 
     p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb"); 
     return p; 
    } 

    @Test 
    public void test() throws Exception { 

     userTransaction.begin(); 

     try { 
      entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); 
      entityManager.persist(new Movie("Joel Coen", "Fargo", 1996)); 
      entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998)); 

      List<Movie> list = movies.getMovies(); 
      assertEquals("List.size()", 3, list.size()); 

      for (Movie movie : list) { 
       movies.deleteMovie(movie); 
      } 

      assertEquals("Movies.getMovies()", 0, movies.getMovies().size()); 

     } finally { 
      userTransaction.commit(); 
     } 
    } 
} 

Full source here

最終的結果

人們很容易把重點放在不同類型的測試,等之間的差異,但肯定有什麼東西了務實的中間可說的。我個人並不認爲能夠儘可能流利地混合「單元」和「集成」的風格。

當然,這是一個令人欽佩的目標。理念和功能要求讓我們更接近非常受歡迎。

+0

大衛您好,非常感謝您的回覆。我也在考慮將兩種方法混合起來,這將有助於收穫這兩種方法的好處。 – Bala

5

實際上有兩種不同類型的測試,你可能要考慮的(不是唯一的)的:

  • 單元測試:你的EJB是在一天結束的POJO,因此您可以使用您的首選單元測試框架(例如JUnit)以及Mockito或EasyMock等模擬框架。
  • 集成測試:這裏您要測試EJB,就好像它們在容器中一樣(不是孤立的),因此您必須以某種方式模擬該容器。您仍然可以使用您的單元測試框架對您的測試進行編碼(例如JUnit),但現在您正在測試這些EJB在容器中的行爲以及與其他可能具有的協作者(例如,其他EJB)交互的方式。爲此,我會推薦Arquillian
+0

感謝您的輸入。我基本上專注於使用單元測試更簡單,使得它對開發人員來說既優雅又簡單。但是,正如你所提到的,一個更好的方法是使用嵌入式容器的UT和集成測試的組合,因爲UT的兩個階段似乎是一個不錯的方法。 – Bala

3

您可以使用Needle進行Java EE組件的單元測試。

Needle是一個輕量級框架,用於獨立測試容器外部的Java EE組件。它通過分析依賴關係和自動注入模擬對象來減少測試設置代碼。

http://needle.spree.de