我向你提出的建议是不要陷入常见的陷阱,即认为你需要在模拟和使用嵌入式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;
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();
}
}
}
完整源代码
最终结果
很容易集中关注不同类型的测试之间的差异,但显然有些事情可以说是务实的。个人而言,我认为能够尽可能流畅地混合“单元”和“集成”样式没有任何问题。
当然,这是一个值得称赞的目标。为了让我们更接近,欢迎提供想法和功能请求。