7

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

  1. 我对大型 EJB 实现知之甚少,因此我想先请一些有经验的人(你)来总结你对单元测试 EJB 中难点的想法。
  2. 通过我已经完成的初步研究,我可以理解使用模拟框架进行单元测试而不是使用嵌入式容器的优势。尽管两者都很好,但在单元测试方面,模拟框架略胜一筹。嵌入式容器当然很好,各有优势,但可能是单元测试的不同阶段。我仍然认为,至少在某些情况下,使用此类框架应该存在一些可以改进的不足。

我希望我可以为单元测试 EJB 制作一个完整的解决方案,一旦完成,我可以在这个论坛上分享。

谢谢你的支持。

4

3 回答 3

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;
    }

完整来源在这里

这会扫描类路径并加载所有 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();
        }
    }
}

完整来源在这里

最终结果

关注不同类型的测试等之间的差异是很诱人的,但对于务实的中间人来说,肯定有一些话要说。我个人认为能够尽可能流利地混合“单元”和“集成”样式没有任何问题。

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

于 2011-10-16T03:43:56.953 回答
5

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

  • 单元测试:您的 EJB 归根结底是 POJO,因此您可以使用您喜欢的单元测试框架(例如 JUnit)以及 Mockito 或 EasyMock 等模拟框架。
  • 集成测试:在这里,您想测试 EJB,就好像它们在容器中(而不是孤立地)一样,因此您必须以某种方式模拟该容器。您仍然可以使用单元测试框架来编写测试代码(例如 JUnit),但是现在您正在测试这些 EJB 在容器中的行为方式以及与它们可能拥有的其他协作者(例如其他 EJB)的交互。为此,我会推荐Arquillian
于 2011-10-18T12:46:55.483 回答
3

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

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

http://needle.spree.de

于 2012-10-28T20:27:40.170 回答