【问题标题】:Unit Testing EJB 3.1单元测试 EJB 3.1
【发布时间】:2011-10-14 09:32:27
【问题描述】:

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

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

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

感谢您的支持。

【问题讨论】:

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


    【解决方案1】:

    我对您的建议是不要落入我看到的常见陷阱,即认为您需要在模拟和使用嵌入式 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

    最终结果

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

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

    【讨论】:

    • 您好大卫,非常感谢您的回复。我也在考虑混合使用这两种方法,这将有助于收获这两种方法的好处。
    【解决方案2】:

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

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

    【讨论】:

    • 感谢您的意见。我基本上专注于通过功能使单元测试更简单,以使其对开发人员来说既优雅又容易。但是,正如你也提到的,更好的方法是结合使用嵌入式容器的 UT 和集成测试,因为 UT 的两个阶段似乎是一个不错的方法。
    【解决方案3】:

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

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

    http://needle.spree.de

    【讨论】:

      猜你喜欢
      • 2011-02-15
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多