Java 无法在spring启动测试中模拟persistenceContext
我正在使用带有Mockito框架的spring引导测试来测试我的应用程序。其中一个存储库类EntityManager作为参考 我的班级看起来像下面Java 无法在spring启动测试中模拟persistenceContext,java,spring,unit-testing,jpa,mockito,Java,Spring,Unit Testing,Jpa,Mockito,我正在使用带有Mockito框架的spring引导测试来测试我的应用程序。其中一个存储库类EntityManager作为参考 我的班级看起来像下面 @Repository @Transactional @Slf4j public class SomeRepositoryService { @PersistenceContext private EntityManager entityManager; public
@Repository
@Transactional
@Slf4j
public class SomeRepositoryService {
@PersistenceContext
private EntityManager entityManager;
public List<Run> findBySearchCriteria(String searchCriteria,Integer
offset,Integer limit,Integer userId) {
//code
}
}
当我运行这个时,我会
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.jpa.repository.support.DefaultJpaContext]: Constructor threw exception; nested exception is java.lang.NullPointerException
Caused by: java.lang.NullPointerException: null
at org.springframework.data.jpa.repository.support.DefaultJpaContext.<init>(DefaultJpaContext.java:53) ~[spring-data-jpa-2.0.9.RELEASE.jar:2.0.9.RELEASE]
原因:org.springframework.beans.beans实例化异常:未能实例化[org.springframework.data.jpa.repository.support.DefaultJpaContext]:构造函数引发异常;嵌套异常是java.lang.NullPointerException
原因:java.lang.NullPointerException:null
在org.springframework.data.jpa.repository.support.DefaultJpaContext.(DefaultJpaContext.java:53)~[spring-data-jpa-2.0.9.RELEASE.jar:2.0.9.RELEASE]
有人能告诉我如何测试或解决此问题吗?您可以使用
TestEntityManager
而不是模拟:
@Autowired
private TestEntityManager entityManager;
@Autowired
private RunRepositoryService runRepositoryService;
@Test
public void testFindBySearchCriteria() {
// 1. Create needed objects and persist them using the test entity manager
// 2. Test your repository method
}
您还需要使用
@DataJpaTest
注释您的测试,以使其正常工作 您可以使用JMockit轻松模拟用@PersistentContext注释的依赖项
@RunWith(JMockit.class)
public class RunRepositoryServiceTests {
@Mocked EntityManager entityManager;
private RunRepositoryService runRepositoryService;
@Before
public void setup(){
runRepositoryService = new RunRepositoryService();
Deencapsulation.setField(runRepositoryService, entityManager); //because its a private field
}
@Test
public void testFindBySearchCriteria(@Mocked Query mockQuery) {
//random fake values for input args
String searchCriteria = "";
Integer offset = 1;
Integer limit = 2;
Integer userId = 1;
//fake object for output arg
List<Run> runList = new ArrayList<Run>();
new Expectations(){{
entityManager.someMethodToMock(argumentMatchers);
result = mockQuery;
times = 1;
//remaining expactations in your code, which will eventually return result
}};
//call method to test
List<Run> result = runRepositoryService.findBySearchCriteria(searchCriteria, offset, limit, userId);
//assertions
assertEquals(runList, result);
}
}
@RunWith(JMockit.class)
公共类RunRepositoryServiceTests{
@模拟实体管理器实体管理器;
专用RunRepositoryService RunRepositoryService;
@以前
公共作废设置(){
runRepositoryService=新的runRepositoryService();
setField(runRepositoryService,entityManager);//因为它是一个私有字段
}
@试验
public void testFindBySearchCriteria(@Mocked Query mockQuery){
//输入参数的随机伪值
字符串searchCriteria=“”;
整数偏移=1;
整数极限=2;
整数userId=1;
//输出参数的伪对象
List runList=new ArrayList();
新期望(){{
entityManager.someMethodToMock(argumentMatchers);
结果=模拟查询;
次数=1;
//代码中剩余的表达式,最终将返回结果
}};
//调用方法进行测试
列表结果=runRepositoryService.findBySearchCriteria(搜索条件、偏移量、限制、用户ID);
//断言
assertEquals(运行列表、结果);
}
}
您可以在不使用@DataJpaTest的情况下使用SpringRunner。这对我很有用:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DataRepository.class, EntityManager.class,
EntityManagerFactory.class})
public class DataRepositoryTest {
@MockBean
private EntityManager entityManager;
@MockBean
private EntityManagerFactory entityManagerFactory;
@Autowired
private DataRepository repository;
@Before
public void setup() {
Mockito.when(entityManagerFactory.createEntityManager()).thenReturn(entityManager);
}
@Test
public void resultTest() {
Query q = mock(Query.class);
when(q.setParameter(anyString(), any())).thenReturn(q);
when(q.getResultList()).thenReturn(createMockReponse());
when(entityManager.createQuery(anyString())).thenReturn(q);
Result r = repository.callQuery();
}
}
我遇到了一个类似的问题,为了解决这个问题,我不得不使用Springs ReflectionTestUtils来注入模拟:
@RunWith(SpringJUnit4ClassRunner.class)
public class RunRepositoryServiceTests {
private EntityManager entityManagerMock;
@Autowired
private RunRepositoryService runRepositoryService;
@Before
public void setUp () {
entityManagerMock = Mockito.mock(EntityManager.class);
ReflectionTestUtils.setField(runRepositoryService, "entityManager", entityManagerMock);
}
@Test
public void testFindBySearchCriteria() {
....
when(entityManagerMock.anyMethodToMock(anyObject())).thenReturn(...);
....
}
}
您不能使用@Autowired
。您需要在测试类中的RunRepositoryService上使用@InjectMocks
。您可以在SpringBootTest中使用它。我试过了。很有效,谢谢。但是如果我不能得到一个基于Mockito的答案,我会接受的。试过了。。我得到了这个例外。。原因:java.lang.IllegalStateException:无法将数据源替换为用于测试的嵌入式数据库。如果您想要一个嵌入式数据库,请在类路径上放置一个受支持的数据库,或者调整@AutoConfigureTestDatabase的replace属性。
@RunWith(SpringJUnit4ClassRunner.class)
public class RunRepositoryServiceTests {
private EntityManager entityManagerMock;
@Autowired
private RunRepositoryService runRepositoryService;
@Before
public void setUp () {
entityManagerMock = Mockito.mock(EntityManager.class);
ReflectionTestUtils.setField(runRepositoryService, "entityManager", entityManagerMock);
}
@Test
public void testFindBySearchCriteria() {
....
when(entityManagerMock.anyMethodToMock(anyObject())).thenReturn(...);
....
}
}