使用 mockito 模拟实体管理器并测试无状态 EJB
Using mockito to mock the entity manager and test a stateless EJB
所以我是使用 mockito 进行测试的新手,我已经查阅了一些教程,但我理解起来很慢。
我有一个由 EJB 支持的端点。我想测试中的方法
EJB。我尝试了很多选项,显然我得到了一个空指针异常。 (我知道什么是
空指针异常是)。模拟的实体管理器不会保留对象。所以它给了我
当我尝试对空列表执行任何操作时出现空指针异常。请任何人都可以展示
我如何解决这个问题,或者指出我可以阅读的任何详细文章或教程以促进我的学习。谢谢大家。
这是我的ejb。
@Stateless
public class CustomerHandler {
@PersistenceContext
private EntityManager em;
public Response borrowMovie(List<RequestMovieDto> borrow) {
borrow.forEach(movies -> {
final Movie movie = findMovieByName(movies.getName());
movie.setAvailableCopies((movie.getAvailableCopies()) - movies.getAmount());
em.merge(movie);
});
return Response.ok(borrow).build();
}
public Movie findMovieByName(String name) {
return em.createQuery("SELECT m FROM Movie m "
+ "WHERE m.name = :name", Movie.class)
.setParameter("name", name)
.getSingleResult();
}
}
and this is my test class
@RunWith(MockitoJUnitRunner.class)
public class MovieHandlerTest {
@Mock
EntityManager manager;
private List<RequestMovieDto> request;
@InjectMocks
CustomerHandler handler;
@Before
public void setUp() {
final Movie first = new Movie();
first.setName("MISSION IMPOSSIBLE");
first.setAvailableCopies(10);
first.setIsbn("ABC788900");
manager.persist(first);
final Movie second = new Movie();
first.setName("JAMES BOND");
first.setAvailableCopies(10);
first.setIsbn("ABC788999");
manager.persist(second);
final Movie last = new Movie();
first.setName("HARRY POTTER");
first.setAvailableCopies(10);
first.setIsbn("ABC7882000");
manager.persist(last);
}
@Test
public void borrowMovie() {
RequestMovieDto first = new RequestMovieDto();
first.setName("MISSION IMPOSSIBLE");
first.setAmount(2);
RequestMovieDto second = new RequestMovieDto();
second.setName("JAMES BOND");
second.setAmount(1);
request = Arrays.asList(first, second);
final var response = handler.borrowMovie(request);
assertEquals(Response.Status.OK, response.getStatusInfo().toEnum());
}
}
为避免 NullPointerException,您可以尝试在 MovieHandlerTest class 中添加以下代码:
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
[..]
@Mock
EntityManager manager;
@Mock
TypedQuery<Movie> query;
[..]
@Before
public void setUp() {
final Movie first = new Movie();
first.setName("MISSION IMPOSSIBLE");
first.setAvailableCopies(10);
first.setIsbn("ABC788900");
final Movie second = new Movie();
first.setName("JAMES BOND");
first.setAvailableCopies(10);
first.setIsbn("ABC788999");
final Movie last = new Movie();
first.setName("HARRY POTTER");
first.setAvailableCopies(10);
first.setIsbn("ABC7882000");
when(manager.createQuery(any(String.class), eq(Movie.class))).thenReturn(query);
when(query.setParameter(any(String.class), any(String.class))).thenReturn(query);
when(query.getSingleResult()).thenReturn(first, second, last);
}
但是 "Response.ok(borrow).build()"
又出现了另一个问题
您有 3 个解决方案:
- 重构代码以引入执行借用工作流的 class 和 returns 模型,然后对该 class
进行单元测试
- 添加带有测试范围的 JAX-RS 实现,例如 Jersey
- 由于无法单独使用 Mockito 模拟静态方法,您可以尝试
添加另一个测试库,例如 PowerMockito,并模拟 Reponse 静态方法调用。
对于方案二,可以添加如下maven依赖:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.13</version>
<scope>test</scope>
</dependency>
所以我是使用 mockito 进行测试的新手,我已经查阅了一些教程,但我理解起来很慢。 我有一个由 EJB 支持的端点。我想测试中的方法 EJB。我尝试了很多选项,显然我得到了一个空指针异常。 (我知道什么是 空指针异常是)。模拟的实体管理器不会保留对象。所以它给了我 当我尝试对空列表执行任何操作时出现空指针异常。请任何人都可以展示 我如何解决这个问题,或者指出我可以阅读的任何详细文章或教程以促进我的学习。谢谢大家。
这是我的ejb。
@Stateless
public class CustomerHandler {
@PersistenceContext
private EntityManager em;
public Response borrowMovie(List<RequestMovieDto> borrow) {
borrow.forEach(movies -> {
final Movie movie = findMovieByName(movies.getName());
movie.setAvailableCopies((movie.getAvailableCopies()) - movies.getAmount());
em.merge(movie);
});
return Response.ok(borrow).build();
}
public Movie findMovieByName(String name) {
return em.createQuery("SELECT m FROM Movie m "
+ "WHERE m.name = :name", Movie.class)
.setParameter("name", name)
.getSingleResult();
}
}
and this is my test class
@RunWith(MockitoJUnitRunner.class)
public class MovieHandlerTest {
@Mock
EntityManager manager;
private List<RequestMovieDto> request;
@InjectMocks
CustomerHandler handler;
@Before
public void setUp() {
final Movie first = new Movie();
first.setName("MISSION IMPOSSIBLE");
first.setAvailableCopies(10);
first.setIsbn("ABC788900");
manager.persist(first);
final Movie second = new Movie();
first.setName("JAMES BOND");
first.setAvailableCopies(10);
first.setIsbn("ABC788999");
manager.persist(second);
final Movie last = new Movie();
first.setName("HARRY POTTER");
first.setAvailableCopies(10);
first.setIsbn("ABC7882000");
manager.persist(last);
}
@Test
public void borrowMovie() {
RequestMovieDto first = new RequestMovieDto();
first.setName("MISSION IMPOSSIBLE");
first.setAmount(2);
RequestMovieDto second = new RequestMovieDto();
second.setName("JAMES BOND");
second.setAmount(1);
request = Arrays.asList(first, second);
final var response = handler.borrowMovie(request);
assertEquals(Response.Status.OK, response.getStatusInfo().toEnum());
}
}
为避免 NullPointerException,您可以尝试在 MovieHandlerTest class 中添加以下代码:
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
[..]
@Mock
EntityManager manager;
@Mock
TypedQuery<Movie> query;
[..]
@Before
public void setUp() {
final Movie first = new Movie();
first.setName("MISSION IMPOSSIBLE");
first.setAvailableCopies(10);
first.setIsbn("ABC788900");
final Movie second = new Movie();
first.setName("JAMES BOND");
first.setAvailableCopies(10);
first.setIsbn("ABC788999");
final Movie last = new Movie();
first.setName("HARRY POTTER");
first.setAvailableCopies(10);
first.setIsbn("ABC7882000");
when(manager.createQuery(any(String.class), eq(Movie.class))).thenReturn(query);
when(query.setParameter(any(String.class), any(String.class))).thenReturn(query);
when(query.getSingleResult()).thenReturn(first, second, last);
}
但是 "Response.ok(borrow).build()"
又出现了另一个问题您有 3 个解决方案:
- 重构代码以引入执行借用工作流的 class 和 returns 模型,然后对该 class 进行单元测试
- 添加带有测试范围的 JAX-RS 实现,例如 Jersey
- 由于无法单独使用 Mockito 模拟静态方法,您可以尝试 添加另一个测试库,例如 PowerMockito,并模拟 Reponse 静态方法调用。
对于方案二,可以添加如下maven依赖:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.13</version>
<scope>test</scope>
</dependency>