如何使用TomEE测试EJB?

时间:2017-09-10 05:10:59

标签: jpa intellij-idea tomee

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

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

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

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

然后使用@BeforeClass 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

虽然我没有使用entityManager,但我遇到了这个错误。如何正确添加一些postgresql属性以正确实例化我的Hibernate 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>

console.clear();

var counters = [];
$.ajax({
  async: true,
  dataType: "json",
  url: "https://api.myjson.com/bins/n1cwx",
  success: function(data) {
    $.each(data, function (i, object) {  
      console.log(object.last_activity_at);
      if (!object.last_activity_at) return; 
      var count= 0;
      var arr = [];
      for (var key in data){
        var date1 = new Date(data[key].last_activity_at).setHours(0,0,0,0);
        var date2 = new Date(object.last_activity_at).setHours(0,0,0,0);
        if(date1 === date2){
          count += 1;
        }
      };
      $("body").append("<p>" + count + "</p>");
      console.log(count);
      console.log(arr);
     $("body").append("<p>" + object.last_activity_at + "</p>");

    });
  }
});

1 个答案:

答案 0 :(得分:1)

我使用TomEE嵌入式容器进行单元测试取得了成功。与任何外部JUnit资源一样,它可以使用@Rule进行管理,因此我有两个类,Rule类和Embedded 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();
    }
}

JUnit规则,用于在执行每个测试之前启动嵌入式TomEE。我们还有一些逻辑可以避免每次测试启动和停止容器的成本。该类还创建了一个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>