单元测试 EJB 3.1

发布于 2024-12-09 13:32:44 字数 361 浏览 1 评论 0原文

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

  1. 我对大型 EJB 实现了解不多,因此我想首先请一些经验丰富的人员(您)来集中讨论单元测试 EJB 中的困难之处。
  2. 通过我已经完成的初步研究,我可以理解使用模拟框架进行单元测试而不是使用嵌入式容器的优势。尽管两者都很好,但在单元测试方面,模拟框架略胜一筹。嵌入式容器当然非常好并且有自己的优点,但是可能是单元测试的不同阶段。我仍然认为,使用此类框架至少在某些场景下应该存在一些不足,可以改进。

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

感谢您的支持。

I am doing a small research on Unit Testing of EJB 3.1. At the end my goal is to produce a easy to use solution for Unit Testing EJB 3.1.

  1. I do not have much knowledge with big EJB implementations and hence I would like to first get some experienced hands (You) to just pool in your ideas on what is difficult in Unit Testing EJBs.
  2. With the initial research I have already done, I can understand the advantages of using mocking frameworks for Unit Testing rather than using embedded containers. Though both are good, mocking frameworks stands a little above when it comes to Unit Testing. The embedded containers are ofcourse very good and have their own advantages, but may be a different phase of unit testing. I still believe that there should be some shortfalls at least in some scenarios in using such frameworks which can be improved.

I hope I could make a complete solution for Unit Testing EJB which I can share in this forum once done.

Thanks for your support.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

街角卖回忆 2024-12-16 13:32:44

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

完整源代码在这里

最终结果

人们很容易关注不同类型测试之间的差异等,但对于务实的中间确实有一些话要说。我个人并不认为能够尽可能流畅地混合“单元”和“集成”风格有什么问题。

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

My advice to you would be to not fall into the common trap I see, which is to think you need to chose between mocking and using an embedded EJB container.

You can use both, you should use both, and where you find it difficult to use both you should demand better support and more features from your EJB container.

Certainly, you will find people at OpenEJB really supportive and more than happy to add features to support getting the best of both worlds. Nearly all the really good features have been created around the requests of users trying to do very specific things and finding it hard.

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

Full source here

This scans the classpath and loads all beans.

No-scanning, easier mocking approach

Slightly different approach where you define everything in code. Obviously mocking is easier as you can supply mock implementations of beans where needed at will.

@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

The end result

It's tempting to focus on the differences between different types of testing, etc. but certainly there's something to be said for a pragmatic middle. I personally don't see anything wrong with being able to mix "unit" and "integration" styles as fluently as possible.

Certainly, it's an admirable goal. Ideas and feature requests to get us closer are very welcome.

物价感观 2024-12-16 13:32:44

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

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

There are actually two different types of testing you might want to consider (not exclusive):

  • Unit Testing: Your EJBs are POJOs at the end of the day and therefore you can use your preferred unit testing framework (e.g. JUnit) and also a mocking framework like Mockito or EasyMock.
  • Integration testing: here you want to test the EJBs as if they were in the container (not in isolation) and therefore you have to somehow emulate that container. You can still use your unit testing framework to code your tests (e.g. JUnit), but now you are testing how these EJBs behave in the container and interact with other collaborators (e.g. other EJBs) they might have. For this I would recommend Arquillian
远昼 2024-12-16 13:32:44

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

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

http://needle.spree.de

You can use Needle for unit tests of Java EE components.

Needle is a lightweight framework for testing Java EE components outside of the container in isolation. It reduces the test setup code by analysing dependencies and automatic injection of mock objects.

http://needle.spree.de

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文