I have following test:
@SpringBootTest(classes = {SomeService.class, DtoMapperImpl.class})
class SomeServiceTest {
And following mapper:
@Mapper(componentModel = "spring")
public interface DtoMapper {
EntityDto toDto(Entity entity);
}
I'm not changing packages (this means DtoMapperImpl is in the same package as DtoMapper)
As soon as I change Impl to interface my test fails:
@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: {}
Can you please advise best way solving this? I'm on MapStruct 1.3.1.Final
The problem actually has nothing to do with MapStruct, but rather to how SpringBootTest#classes
is used.
The classes
in SpringBootTest
is meant to provide your components that should be used to load in the test.
From the 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
In your case you have 2 classes:
SomeService
- which I assume is a class annotated with @Service
and Spring will correctly load itDtoMapper
- this is the MapStruct mapper which is an interface and it isn't a component. The component which you want for your tests is DtoMapperImpl
You have several options to fix this:
You can use the DtoMapperImpl
(the Spring Component class) in your SpringBootTest#classes
, your test will then load the correct component
@TestConfiguration
@ComponentScan("com.example.mapper")
public class MappersConfig {
}
And then use this in your SpringBootTest#classes
. E.g.
@SpringBootTest(classes = {SomeService.class, MappersConfig.class})
class SomeServiceTest {
...
}