【问题标题】:How to test EJB with TomEE?如何使用 TomEE 测试 EJB?
【发布时间】:2017-09-10 05:10:58
【问题描述】:

我正在使用 TomEE 和 Intellij 来测试我的 EJB/JPA bean。我在this answer 上看到我应该使用嵌入式容器进行测试。我在this other answer(来自同一个问题)上发现了 Arquillian,但正如 cmets 所述,设置起来很困难,而且对用户不友好,像我这样的初学者搜索的东西。

不幸的是,我没有使用glassfish-embedded-all 依赖作为回答,而是tomee-embedded。我在这个official tutorial 上看到它应该使用 JTA 以及上面的回答。但为什么呢?

作为最后一个链接,我收到了这个错误:

No EJBContainer provider available: no provider names had been found.

然后使用来自@BeforeClass 方法的一段代码来自这个answer。我的测试如下所示:

    Properties properties = new Properties();
    properties.setProperty(EJBContainer.PROVIDER, "tomee-embedded");
    EJBContainer container = EJBContainer.createEJBContainer(properties);
    AccountDao dao = (AccountDao) container.getContext().lookup("java:global/Test/AccountDao");

Test 是我的应用程序名称,AccountDao 是我想要测试的 Stateless Bean。但现在我收到了这个错误:

Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: PG_CLASS

虽然我没有使用HSQLDB,但我遇到了这个错误。如何正确添加一些 postgresql 属性以正确实例化我的 Hibernate entityManager?这是我的persistence.xml

<persistence-unit name="unitName">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <class>entity.PersistentEntity.Account</class>
    <properties>
        <property name="tomee.jpa.factory.lazy" value="true"/>
        <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/click10"/>
        <property name="javax.persistence.jdbc.user" value="postgres"/>
        <property name="javax.persistence.jdbc.password" value="postgres"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
    </properties>
</persistence-unit>

【问题讨论】:

    标签: jpa intellij-idea apache-tomee


    【解决方案1】:

    我已成功使用 TomEE 嵌入式容器进行单元测试。与任何外部 JUnit 资源一样,它可以使用@Rule 进行管理,因此我有两个类,即规则类和嵌入式 TomEE 的包装器。

    TomEE Container 类的包装类。配置嵌入式 derby 数据源和用户,以便我们可以测试基本身份验证。

    /**
     * class for starting an Embedded TomEE server which will scan the classpath and start the application.
     * The configuration configures an InMemory derby database, and tells JPA to create tables based on the Entity annotations
     *
     */
    public class EmbeddedTomEE {
    
        public static final String USERNAME = "aUser";
        public static final String PASSWORD = "aPassword";
        private Container container;
    
        public void start() {
            Configuration configuration = new Configuration();
            Properties properties = new Properties();
            properties.setProperty("jdbc/UdDB", "new://Resource?type=DataSource");
            properties.setProperty("jdbc/UdDB.jdbcDriver", "org.apache.derby.jdbc.EmbeddedDriver");
            properties.setProperty("jdbc/UdDB.jdbcUrl", "jdbc:derby:memory:udb;create=true");
            properties.setProperty("jdbc/UdDB.username", "SA");
            properties.setProperty("jdbc/UdDB.password", "");
            properties.setProperty("jdbc/UdDB.jtaManaged", "true");
            properties.setProperty("persistence_unit.javax.persistence.schema-generation.database.action", "create");
            properties.setProperty("persistence_unit.javax.persistence.sql-load-script-source", "META-INF/testdata.sql");
            properties.setProperty("rest-persistence_unit.eclipselink.logging.level", "FINE");  //use 'FINE' for JPA logging
    
            configuration.setProperties(properties);
            // use a random port so we can have TomEE running parallel with tests
            configuration.randomHttpPort();
            configuration.setWebXml("src/main/webapp/WEB-INF/web.xml");
    
            HashMap<String, String> users = new HashMap<>();
            users.put(USERNAME, PASSWORD);
            configuration.setUsers(users);
            HashMap<String, String> roles = new HashMap<>();
            roles.put("aUser", "user");
            configuration.setRoles(roles);
            container = new Container(configuration).deployClasspathAsWebApp();
        }
    
        public int getPort() {
            return container.getConfiguration().getHttpPort();
        }
    
        public void stop() {
            container.close();
        }
    }
    

    在执行每个测试之前负责启动嵌入式 TomEE 的 JUnit 规则。我们也有一些逻辑来避免每次测试启动和停止容器的成本。该类还创建一个 JAX-RS webClient,可用于调用应用程序 REST 服务。

    /**
     * JUnit rule for running an EmbeddedTomEE in memory. The rule has static state, this is to avoid starting and stopping the embedded container
     * with every test. Every time no test are running we start a timer, which is canceled if another test is started. This way the rule works well for a
     * single test run inside an IDE, and running multiple tests from Maven.
     *
     */
    public class EmbeddedTomEERule extends ExternalResource {
    
        private static EmbeddedTomEE tomEE;
        private static final AtomicInteger count = new AtomicInteger();
        private static Timer timer;
    
        @Override
        protected void before() throws Throwable {
            startIfNeeded();
            if (timer != null) {
                timer.cancel();
            }
            count.incrementAndGet();
        }
    
        @Synchronized
        private void startIfNeeded() {
            if (tomEE == null) {
                tomEE = new EmbeddedTomEE();
                tomEE.start();
                Runtime.getRuntime().removeShutdownHook(new Thread(() -> tomEE.stop()));
            }
        }
    
        @Override
        protected void after() {
            int runningTests = count.decrementAndGet();
            if (runningTests == 0) {
                // stop after some time if no new test are started
                timer = new Timer();
                timer.schedule(new StopEmbeddedContainer(), 10000);
            }
        }
    
        public int getPort() {
            return tomEE.getPort();
        }
    
        /**
         * creates a new WebClient that can request data from the specified path
         */
        public WebClient getWebClient(String path, MediaType mediatype) {
            WebClient client = WebClient.create("http://localhost:" + tomEE.getPort() + "/", Collections.singletonList(new JohnzonProvider()),
                    EmbeddedTomEE.USERNAME, EmbeddedTomEE.PASSWORD, null)
    
                    .path(path).accept(mediatype);
            return client;
        }
    
        private static class StopEmbeddedContainer extends TimerTask {
            @Override
            public void run() {
                tomEE.stop();
            }
        }
    }
    

    这是一个测试的外观示例

    public class ExampleTest {
    
        @Rule
        public EmbeddedTomEERule rule = new EmbeddedTomEERule();
    
        @Test
        public void doTest() {
    
            WebClient client = rule.getWebClient("some-endpoint", MediaType.APPLICATION_JSON_TYPE);
            Output dto = client.get(Input.class);
        }
    }
    

    这种类型的测试允许您在 HTTP 层测试您的应用程序,它允许您在测试和服务器代码中放置断点。从技术上讲,将其称为单元测试可能有点牵强,但在测试多个组件时,我更喜欢这种类型的测试。由于您需要一个功能齐全的 TomEE,您将需要提供许多外部依赖项,在我的例子中,它看起来像这样:

    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derby</artifactId>
        <version>${derby.db.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>openejb-core</artifactId>
        <version>${openejb-core.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>openejb-cxf-rs</artifactId>
        <version>${openejb-core.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>openejb-server</artifactId>
        <version>${openejb-core.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>openejb-rest</artifactId>
        <version>${openejb-core.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>tomee-embedded</artifactId>
        <version>${openejb-core.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>el-impl</artifactId>
        <version>2.2</version>
        <scope>test</scope>
    </dependency>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多