最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - How to inject a Mapper from MapStruct into a @WebMockMVC Integration Test - Stack Overflow

programmeradmin1浏览0评论

I am trying to test a Spring Boot Controller, the controller has an UserService dependency and the UserService has an UserMapper dependency, the code compiles and run flawless, but when trying to run the test below i get an error:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userControllerImpl': 
Unsatisfied dependency expressed through field 'userMapper': Error creating bean with name 'com.acneUserMapper':
 Failed to instantiate [com.acne.user.UserMapper]: Specified class is an interface

test:

@WebMvcTest(UserController.class)
@Import(UserMapper.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@AutoConfigureWebMvc
public class UserControllerTests {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void shouldGetAuthenticatedUser() throws Exception {
        this.mockMvc.perform(get("/api/users/me").with(oidcLogin())).andExpect(status().isOk());
    }
}

UserMapper:

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface UserMapper {
    public UserResponseDTO toUserResponseDTO(UserEntity userEntity);

    public UserDTO toDto(UserEntity entity);

    public UserEntity toEntity(UserDTO dto);
}

UserController & Impl:

public interface UserController {

    @GetMapping("/me")
    public ResponseEntity<UserResponseDTO> getCurrentUser(Authentication authentication);
} 
@RestController
public class UserControllerImpl implements UserController {

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserService userService;

    @Override
    public ResponseEntity<UserResponseDTO> getCurrentUser(Authentication currentUser) {
        UserEntity loggedUser = userService.findByLoginOrError(currentUser.getName());
        return ResponseEntity.ok(userMapper.toUserResponseDTO(loggedUser));
    }
}

If i change the test import to @Import(UserMapperImpl.class) the error changes to:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.acne.user.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency a
nnotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

My question is: What can I do to test the controller and spring correctly inject the mapper?

I am trying to test a Spring Boot Controller, the controller has an UserService dependency and the UserService has an UserMapper dependency, the code compiles and run flawless, but when trying to run the test below i get an error:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userControllerImpl': 
Unsatisfied dependency expressed through field 'userMapper': Error creating bean with name 'com.acneUserMapper':
 Failed to instantiate [com.acne.user.UserMapper]: Specified class is an interface

test:

@WebMvcTest(UserController.class)
@Import(UserMapper.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@AutoConfigureWebMvc
public class UserControllerTests {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void shouldGetAuthenticatedUser() throws Exception {
        this.mockMvc.perform(get("/api/users/me").with(oidcLogin())).andExpect(status().isOk());
    }
}

UserMapper:

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface UserMapper {
    public UserResponseDTO toUserResponseDTO(UserEntity userEntity);

    public UserDTO toDto(UserEntity entity);

    public UserEntity toEntity(UserDTO dto);
}

UserController & Impl:

public interface UserController {

    @GetMapping("/me")
    public ResponseEntity<UserResponseDTO> getCurrentUser(Authentication authentication);
} 
@RestController
public class UserControllerImpl implements UserController {

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserService userService;

    @Override
    public ResponseEntity<UserResponseDTO> getCurrentUser(Authentication currentUser) {
        UserEntity loggedUser = userService.findByLoginOrError(currentUser.getName());
        return ResponseEntity.ok(userMapper.toUserResponseDTO(loggedUser));
    }
}

If i change the test import to @Import(UserMapperImpl.class) the error changes to:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.acne.user.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency a
nnotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

My question is: What can I do to test the controller and spring correctly inject the mapper?

Share Improve this question asked Feb 6 at 23:40 udduuudduu 1315 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

Using @WebMvcTest and @MockitoBean for UserService is usually the preferred alternative.

@WebMvcTest(UserController.class)
@Import(UserMapperImpl.class)
class UserControllerTest {

    @MockitoBean
    UserService userService;

    @Autowired
    MockMvc mockMvc;

You will have to implement required methods on the mock like this

when(userService.findByLoginOrError("user1")).thenReturn(<SOME VALUE HERE>);

If you want to mock UserMapper as well, remove @Import(UserMapperImpl.class) and add

    @MockitoBean
    UserMapper userMapper;

Alternative Option

@SpringBootTest and @AutoConfigureMockMvc as documented here.

@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTests {

    @Autowired
    MockMvc mockMvc;

    // remaining code left out

Both @MockitoBean and @MockitoSpyBean can also be used with @SpringBootTest.

Tested on my computer with this in build.gradle.kts:

    compileOnly("org.mapstruct:mapstruct:1.6.3")
    annotationProcessor("org.mapstruct:mapstruct-processor:1.6.3")
发布评论

评论列表(0)

  1. 暂无评论