带有 MapStruct 的 @SpringBootTest 需要 Impl
@SpringBootTest with MapStruct requires Impl
我有以下测试:
@SpringBootTest(classes = {SomeService.class, DtoMapperImpl.class})
class SomeServiceTest {
以及以下映射器:
@Mapper(componentModel = "spring")
public interface DtoMapper {
EntityDto toDto(Entity entity);
}
我没有更改包(这意味着 DtoMapperImpl 与 DtoMapper 在同一个包中)
一旦我将 Impl 更改为接口,我的测试就失败了:
@SpringBootTest(classes = {SomeService.class, DtoMapper.class})
class SomeServiceTest {
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'someService': Unsatisfied dependency
expressed through constructor parameter 2; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'DtoMapper' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations: {}
能否请您建议解决此问题的最佳方法?我在 MapStruct 1.3.1.Final
创建以下配置(应指向映射器所在的位置):
@TestConfiguration
@ComponentScan("some.package.mapper")
public class MappersConfig {
}
并修改切片:
@SpringBootTest(classes = {SomeService.class, MappersConfig.class})
class SomeServiceTest {
问题实际上与 MapStruct 无关,而是与 SpringBootTest#classes
的使用方式有关。
SpringBootTest
中的 classes
旨在提供您应该用于在测试中加载的组件。
来自 JavaDoc:
The component classes to use for loading an ApplicationContext
. Can also be specified using @ContextConfiguration(classes=...)
. If no explicit classes are defined the test will look for nested @Configuration
classes, before falling back to a @SpringBootConfiguration
search.
Returns:
the component classes used to load the application context
在你的例子中你有 2 个 classes:
SomeService
- 我假设是 class 注释 @Service
并且 Spring 将正确加载它
DtoMapper
- 这是 MapStruct 映射器,它是一个接口,而不是一个组件。您想要用于测试的组件是 DtoMapperImpl
您有多种选择来解决此问题:
使用 Impl class
您可以在 SpringBootTest#classes
中使用 DtoMapperImpl
(Spring 组件 class),然后您的测试将加载正确的组件
使用自定义配置 class 将组件扫描您的映射器
@TestConfiguration
@ComponentScan("com.example.mapper")
public class MappersConfig {
}
然后在您的 SpringBootTest#classes
中使用它。例如
@SpringBootTest(classes = {SomeService.class, MappersConfig.class})
class SomeServiceTest {
...
}
我有以下测试:
@SpringBootTest(classes = {SomeService.class, DtoMapperImpl.class})
class SomeServiceTest {
以及以下映射器:
@Mapper(componentModel = "spring")
public interface DtoMapper {
EntityDto toDto(Entity entity);
}
我没有更改包(这意味着 DtoMapperImpl 与 DtoMapper 在同一个包中)
一旦我将 Impl 更改为接口,我的测试就失败了:
@SpringBootTest(classes = {SomeService.class, DtoMapper.class})
class SomeServiceTest {
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'someService': Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'DtoMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
能否请您建议解决此问题的最佳方法?我在 MapStruct 1.3.1.Final
创建以下配置(应指向映射器所在的位置):
@TestConfiguration
@ComponentScan("some.package.mapper")
public class MappersConfig {
}
并修改切片:
@SpringBootTest(classes = {SomeService.class, MappersConfig.class})
class SomeServiceTest {
问题实际上与 MapStruct 无关,而是与 SpringBootTest#classes
的使用方式有关。
SpringBootTest
中的 classes
旨在提供您应该用于在测试中加载的组件。
来自 JavaDoc:
The component classes to use for loading an
ApplicationContext
. Can also be specified using@ContextConfiguration(classes=...)
. If no explicit classes are defined the test will look for nested@Configuration
classes, before falling back to a@SpringBootConfiguration
search. Returns: the component classes used to load the application context
在你的例子中你有 2 个 classes:
SomeService
- 我假设是 class 注释@Service
并且 Spring 将正确加载它DtoMapper
- 这是 MapStruct 映射器,它是一个接口,而不是一个组件。您想要用于测试的组件是DtoMapperImpl
您有多种选择来解决此问题:
使用 Impl class
您可以在 SpringBootTest#classes
中使用 DtoMapperImpl
(Spring 组件 class),然后您的测试将加载正确的组件
使用自定义配置 class 将组件扫描您的映射器
@TestConfiguration
@ComponentScan("com.example.mapper")
public class MappersConfig {
}
然后在您的 SpringBootTest#classes
中使用它。例如
@SpringBootTest(classes = {SomeService.class, MappersConfig.class})
class SomeServiceTest {
...
}