我试图用Mock运行一个控制器级的Spring Boot单元测试,用于我的服务层依赖。但是,这个Mock需要一个使用EntityManager
对象的下游存储库依赖项,这会导致我的测试在加载ApplicationContext
时失败。
我的测试不涉及存储库依赖项或EntityManager
,它使用Mocked服务对象返回一个预设响应。如果我只想模拟服务层对象,为什么Spring会抱怨repo / EntityManager
?
控制器单元测试代码:
@RunWith(SpringRunner.class)
@WebMvcTest
@AutoConfigureWebClient
public class MobileWearControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
UserDeviceService userDeviceService;
//.....
}
UserDeviceService代码:
@Service
public class UserDeviceService {
private UserDeviceRepository userDeviceRepository;
public UserDeviceService(UserDeviceRepository userDeviceRepository) {
this.userDeviceRepository = userDeviceRepository;
}
//....
}
UserDeviceRepository代码:
@Repository
public class UserDeviceRepositoryImpl implements UserDeviceRepositoryCustom {
@PersistenceContext
private EntityManager em;
//....
}
期待测试运行。
实际结果是获得以下堆栈跟踪:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDeviceRepositoryImpl': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available
...
我的问题是我用于测试的注释。
使用@AutoConfigureWebClient尝试站起来整个Spring Context;因为我是单元测试我的控制器,我想只测试web层并模拟下游依赖项(即UserDeviceService)。所以,我应该使用@SpringBootTest和@AutoConfigureMockMvc,它将仅为控制器层设置我的Spring上下文。
使用这种方法,我能够成功地模拟UserDeviceService,从而允许我的测试编译和运行:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MobileWearControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
UserDeviceService userDeviceService;
//...
}
首先,您需要指定要测试的控制器
@WebMvcTest(YourController.class)
此外,使用JUnit5,您不需要配置任何扩展,因为@WebMvcTest
包含@ExtendWith(SpringExtension.class)
。你显然是在JUnit4上,但这不应该造成任何伤害。