Cucumber 步骤 - 使用持久性上下文测试 EJB 服务

Cucumber steps - testing an EJB service with a persistence context

我有一个使用 @PersistenceContextEntityManager 的无状态 EJB,我正在编写一个黄瓜步骤定义 class,它使用此服务来执行测试查找用户的步骤根据提供的标准。

例如

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public void add(String userName) {
        User user = new User(userName);
        em.persist(user);
    }    

    public List<User> findByName(String userName) {
        return em.createQuery("Select u from User as u WHERE u.name LIKE :userName").setParameter("userName", userName).getResultList();
    }

}

还有一个类似于

的功能文件
Feature: Search

    Given a user with the name 'Jason Statham'
        And another user with the name 'Bill Gates'
        And another user with the name 'Larry Page'
    When the customer searches for a user with the name 'Jason'
    Then 1 users should have been found
        And User 1 should have a name of 'Jason Statham'

和步骤定义 class

 public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();
   private UserService userService = new UserService();

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

现在我明白了,因为服务是一个 EJB,所以 EntityManager 被注入了 通过 @PersistenceContext.

我的问题是在步骤定义中我应该如何处理这种依赖关系?我应该模拟它并将这个模拟注入 UserService,还是 UserService 有一个 EntityManager 的 setter 并使用 EntityManagerFactory 创建一个在 SearchStepsDefinitions?

换句话说

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public void add(String userName) {
        User user = new User(userName);
        em.persist(user);
    }    

    public List<User> findByName(String userName) {
        return em.createQuery("Select u from User as u WHERE u.name LIKE :userName").setParameter("userName", userName).getResultList();
    }

    public void setEm(EntityManager em) {
        this.em = em;
    }

}

那么步骤定义就是这样

public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();

   @Mock
   private EntityManager em;       

   @Inject
   @InjectMocks
   private UserService userService;

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

或者这个

public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();

   private UserService userService = new UserService();

   @Before
   public void setup() {
       userService.setEm(Persistence.createEntityManagerFactory("punit").createEntityManager());
   }

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

基本上我正在尝试做与 this example 相同的事情,但我没有使用 Spring

或者另一种选择可能是不将服务作为 EJB 而 @Inject EntityManager

public class UserService {

    @Inject
    private EntityManager em;

    public void add(String userName) {
        User user = new User(userName);
        em.persist(user);
    }    

    public List<User> findByName(String userName) {
        return em.createQuery("Select u from User as u WHERE u.name LIKE :userName").setParameter("userName", userName).getResultList();
    }

}

然后步骤看起来像

 public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();

   @Inject
   private UserService userService;

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

我不太确定这些方法的优缺点?

经过大量挖掘,我发现我需要使用 EJBContainer,然后步骤 class 现在看起来像这样

 public class SearchStepsDefinitions {

   private Context context;
   private EJBContainer container;

   private List<User> userList = new ArrayList<>();

   private UserService userService;

   @cucumber.api.java.Before
   public void setup() {
       ejbContainer = EJBContainer.createEJBContainer();
       context = ejbContainer.getContext();

       userService = (UserService) context.lookup("java:global/classes/UserService");
   }

   @cucumber.api.java.After
   public void teardown() {
       ejbContainer.close();
   }

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

需要的另一件事是 pom.xml 中的 ejb 容器。我使用了具有这种依赖性的 glassfish。

<dependency>
    <groupId>org.glassfish.main.extras</groupId>
    <artifactId>glassfish-embedded-all</artifactId>
    <version>4.1</version>
</dependency>