Mockito @Spy calls real method while mocking behaviour is defined

846 views Asked by At

I have a common spring boot application consisting of a controller and a service layer. A database is not involved as I use another rest api to store the data.

Now I want to the my controller and therefor I want to mock my sevice partially. Partially because I have one method in it that takes a dto and converts it to my business model. I know this can also be solved with a constructor of the bussiness model but anyway I came to the following problem:

CODE

Controller

@RestController
public class RegistrationController {

@Autowired
private UserRegistrationService userRegistrationService;

@PostMapping(value = "/user", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserId> createUser(@RequestBody @Valid UserDto userDto) {
    KeycloakUserRepresentation keycloakUserRepresentation = userRegistrationService.convertUserDtoToKeycloakUserRepresentation(userDto);
    UserId userId = userRegistrationService.createNewUser(keycloakUserRepresentation);
    return new ResponseEntity<>(userId,HttpStatus.CREATED);
}

TEST

@SpringBootTest
@AutoConfigureMockMvc
@ExtendWith({RestDocumentationExtension.class})
@AutoConfigureRestDocs
class RegistrationControllerRegistrationTest {

    private static final UserDto testUsertDto = new UserDto();

    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;
    @Spy
    private UserRegistrationServiceImpl userRegistrationService;

In my test method I define:

doReturn(testUserId).when(userRegistrationService).createNewUser(any(KeycloakUserRepresentation.class));

PROBLEM:

I expect that while not define a doSomething in my test, the conversion of the userDto to a keycloak representation is done by the original method. This seems to work as when I debug in my Controller the keycloakUserRepresentation has the correct values. The problem is that in the next step the

createNewUser

method is not stubbed/mocked. The original method is executed and so my test fails. What I want is that when I provide a doSomething method in my testcase, I want the original method to be mocked.

1

There are 1 answers

0
Michiel On

This seems to work as when I debug in my Controller the keycloakUserRepresentation has the correct values.

It worked because the bean wasn't spied on at all. Although @Spy may help in creating a mocked object, it does not result in a mocked Spring bean in your test application context. Use @SpyBean to have Mockito spy on a bean in the Spring application context.