2011-10-14 69 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