Spring 启动控制器测试:模拟服务需要下游对象导致 ApplicationContext 无法加载

Spring Boot Controller Test: mocking service requiring downstream objects causing ApplicationContext to not load

我正在尝试 运行 控制器级 Spring 启动单元测试,并使用 Mock 对我的服务层依赖项进行测试。但是,此 Mock 需要使用 EntityManager 对象的下游存储库依赖项,这导致我的测试在加载 ApplicationContext 时失败。

我的测试不涉及存储库依赖性或 EntityManager,它使用 Mocked 服务对象来 return 固定响应。为什么 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
...

首先,您需要指定要测试的控制器

@WebMvcTest(YourController.class)

此外,使用 JUnit5,您无需配置任何扩展,因为 @WebMvcTest 包含 @ExtendWith(SpringExtension.class)。您显然使用的是 JUnit4,但这应该不会造成任何伤害。

检查示例https://spring.io/guides/gs/testing-web/

我的问题是我用于测试的注释。

使用@AutoConfigureWebClient 尝试建立整个Spring 上下文;因为我正在对我的控制器进行单元测试,所以我只想测试 Web 层并模拟下游依赖项(即 UserDeviceService)。所以,我应该改用@SpringBootTest 和@AutoConfigureMockMvc,这将为控制器层设置我的Spring上下文。

使用这种方法,我能够让 UserDeviceService 成功模拟,从而允许我的测试编译和 运行:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MobileWearControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    UserDeviceService userDeviceService;

    //...
}