单元测试EJB 3.1

时间:2011-10-14 09:32:27

标签: unit-testing ejb-3.0 mockito ejb-3.1 openejb

我正在对EJB 3.1的单元测试进行一项小型研究。最后,我的目标是为单元测试EJB 3.1生成一个易于使用的解决方案。

  1. 我对大型EJB实现知之甚少,因此我想首先让一些有经验的人(You)将您的想法汇集到单元测试EJB中。
  2. 通过我已经完成的初步研究,我可以理解使用模拟框架进行单元测试而不是使用嵌入式容器的优势。虽然两者都很好,但在单元测试方面,模拟框架略高一些。嵌入式容器非常好,并且各有优势,但可能是单元测试的不同阶段。我仍然认为,至少在使用可以改进的框架的某些情况下应该存在一些不足。
  3. 我希望我能为单元测试EJB制作一个完整的解决方案,一旦完成,我就可以在这个论坛上分享。

    感谢您的支持。

3 个答案:

答案 0 :(得分:14)

我对你的建议是不要陷入我看到的常见陷阱,即认为你需要在模拟和使用嵌入式EJB容器之间进行选择。

您可以同时使用它们,您应该同时使用它们,并且在您发现难以同时使用它们的情况下,您应该要求EJB容器提供更好的支持和更多功能。

当然,你会发现OpenEJB的人真的很支持并且非常乐意添加功能来支持两全其美。几乎所有非常好的功能都围绕着用户的要求创建,这些用户试图做非常具体的事情并且很难找到它。

标准EJBContainer API

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。

无扫描,更容易模拟的方法

在代码中定义所有内容的方法略有不同。显然,模拟更容易,因为你可以随意提供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

最终结果

很容易将注意力集中在不同类型的测试之间的差异等等,但对于一个实用的中间部分来说肯定会有所说。我个人认为能够尽可能流畅地混合“单元”和“集成”样式没有任何问题。

当然,这是一个令人钦佩的目标。非常欢迎让我们更接近的想法和功能要求。

答案 1 :(得分:5)

实际上,您可能需要考虑两种不同类型的测试(非独占):

  • 单元测试:您的EJB在一天结束时是POJO,因此您可以使用首选的单元测试框架(例如JUnit)以及Mockito或EasyMock等模拟框架。
  • 集成测试:在这里,您要测试EJB,就好像它们位于容器中一样(不是孤立的),因此您必须以某种方式模拟该容器。您仍然可以使用单元测试框架来编写测试代码(例如JUnit),但现在您正在测试这些EJB在容器中的行为方式,并与他们可能拥有的其他协作者(例如其他EJB)进行交互。为此,我建议Arquillian

答案 2 :(得分:3)

您可以使用Needle进行Java EE组件的单元测试。

Needle是一个轻量级框架,用于隔离地测试容器外部的Java EE组件。它通过分析依赖关系和自动注入模拟对象来减少测试设置代码。

http://needle.spree.de