user3343543
user3343543

Reputation: 141

How to inject interface in Spring Boot Controller Test?

I have created a Spring Boot Project with RestController. I am looking to test the RestController in SpringBoot. But I am unable to inject interface in Spring Controller Test. I am getting below error.

Please assist.

    Cannot instantiate @InjectMocks field named 'authService'! Cause: the type 'AuthService' is an interface.
You haven't provided the instance at field declaration so I tried to construct the instance.
Examples of correct usage of @InjectMocks:
   @InjectMocks Service service = new Service();
   @InjectMocks Service service;
   //and... don't forget about some @Mocks for injection :)

My Source Code is as follows

AuthService Interface

public interface AuthService {

    AppUser save(RegisterDto registerDto);
}

AuthServiceImpl.java

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AppUserRepository userRepository;

    @Override
    public AppUser save(RegisterDto registerDto) {
        if (userRepository.existsByUsername(registerDto.getUsername())) {
            throw new RuntimeException("Username already taken");
        }

        if (userRepository.existsByEmail(registerDto.getEmail())) {
            throw new RuntimeException("Email address already registered");
        }
        AppUser user = convertToAppUser(registerDto);
        return userRepository.save(user);
    }

    private AppUser convertToAppUser(RegisterDto registerDto) {
        AppUser user = new AppUser(
                registerDto.getFirstName(),
                registerDto.getLastName(),
                registerDto.getUsername(),
                registerDto.getEmail(),
                registerDto.getPassword());
        return user;
    }
}

AuthController.java

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private AuthService authService;

    @PostMapping("/users")
    public AppUser save(@RequestBody RegisterDto registerDto) {
        return authService.save(registerDto);
    }
}

AuthControllerTest.java

@RunWith(SpringRunner.class)
@WebMvcTest(AuthController.class)
public class AuthControllerTest {

    @Autowired
    MockMvc mockMvc;

    @InjectMocks
    private AuthService authService;

    @Test
    public void save_user__success() throws Exception {
        AppUser user = new AppUser("admin", "admin", "admin", "[email protected]", "admin");

        when(authService.save(Mockito.any(RegisterDto.class))).thenReturn(user);

        mockMvc.perform(
                MockMvcRequestBuilders.post("/api/auth/users")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(convertToJson(user)))
                .andExpect(status().isCreated());
    }


    /*
     * converts a Java object into JSON representation
     */
    public static String convertToJson(final Object obj) {
        try {
            return new ObjectMapper().writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Upvotes: 1

Views: 2141

Answers (1)

acdcjunior
acdcjunior

Reputation: 135762

You would use @InjectMocks only in a concrete class object instance (whose real functionality you want to use, only with its dependencies mocked), not on an interface (which generally doesn't have functionality, just a contract, nor an instance).

Since you use when(authService.save(...))).thenReturn(...), what I believe you want is actually @MockBean, so use it instead of @InjectMocks:

@RunWith(SpringRunner.class)
@WebMvcTest(AuthController.class)
public class AuthControllerTest {

    @Autowired
    MockMvc mockMvc;

    @MockBean // replaced @InjectMocks
    private AuthService authService;

    @Test
    public void save_user__success() throws Exception {
        AppUser user = new AppUser("admin", "admin", "admin", "[email protected]", "admin");

        when(authService.save(Mockito.any(RegisterDto.class))).thenReturn(user);

        mockMvc.perform(
            // ...

Upvotes: 2

Related Questions