Mirko Manojlovic
Mirko Manojlovic

Reputation: 73

MapStruct not autowring with Spring-boot testing Gradle Junit5

I am trying to use mapstruct with Gradle, but I am having limited success. When I'm using it in the application everything seems to be working fine, but when I tried to write some tests Spring can't autowire MapStruct properly (it just returns NullPointer exceptions). I am using Gradle 5.4.1, Junit5 and IntelliJ 2019.1.2.

This is the build folder and there is no mapper generated for test classes.

enter image description here

Repository with the code is here: https://github.com/MirkoManojlovic/mapstruct-example

Mapper:

@Mapper(unmappedTargetPolicy = ReportingPolicy.WARN,
        componentModel = "spring",
        injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ItemMapper {
    ItemDto toDto(Item item);
    Item toItem(ItemDto itemDto);
}

Repository:

public class ItemRepository {
    public ItemDto getItemDto() {
        return new ItemDto("item 1");
    }

    public Item getItem() {
        return new Item(1, "item 1", 20);
    }
}

Service:

@Service
@RequiredArgsConstructor
@Log4j2
public class ItemService {
    private final ItemRepository itemRepository;
    private final ItemMapper itemMapper;

    public ItemDto getItemDto() {
        Item item = itemRepository.getItem();
        ItemDto itemDto = itemMapper.toDto(item);
        log.info(itemDto);
        return itemDto;
    }

    public Item getItem() {
        ItemDto itemDto = itemRepository.getItemDto();
        Item item = itemMapper.toItem(itemDto);
        log.info(item);
        return item;
    }
}

Test:

@ExtendWith(MockitoExtension.class)
public class ItemServiceTest {

    @Mock
    private ItemRepository itemRepository;

    @InjectMocks
    private ItemService itemService;

    @Spy
    private ItemMapper itemMapper;

    @Test
    void shouldReturnItemDto() {
        Item mockItem = new Item(1, "mockItem", 10);
        given(itemRepository.getItem()).willReturn(mockItem);
        ItemDto itemDto = itemService.getItemDto();
        assertThat(mockItem.getName()).isEqualTo(itemDto.getName());
    }

}

build.gradle:

plugins {
    id 'org.springframework.boot' version '2.1.5.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.mapstruct.spring.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

test {
    useJUnitPlatform {
    }
}

dependencies {
    // Mapstruct
    implementation 'org.mapstruct:mapstruct:1.3.0.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.3.0.Final'
    testAnnotationProcessor 'org.mapstruct:mapstruct-processor:1.3.0.Final'

    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation('org.springframework.boot:spring-boot-starter-test')

    // JUnit5
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.2'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.3.2'

    // Mockito
    testImplementation 'org.mockito:mockito-core:2.23.4'
    testImplementation 'org.mockito:mockito-junit-jupiter:2.23.4'
}

Upvotes: 5

Views: 4316

Answers (1)

Alexander Petrov
Alexander Petrov

Reputation: 9492

@Spy annotation on

@Spy
private ItemMapper itemMapper;

will not perform dependency injection of the generated ItemMapperImpl class file. The solution would be to set

 @Spy
 private ItemMapper itemMapper = Mappers.getMapper(ItemMapper.class);

Or alternativly to enable spring dependency injection via @SpringBootTest(classes = {ItemMapperImpl.class}).

Upvotes: 4

Related Questions