Reputation: 33
I'm trying to understand how to use Mockito in a Spring project, but I'm a bit stuck with the following:
I'm about to test a service with a real (in-memory) repository. I'm mocking every other object that's being used by that service. If I understand correctly, annotating an object with @Mock
will be mocked, @Spy
will use a real object, and with @InjectMocks
will kind of "autowire" these annotated objects. However, I think I misunderstood @Spy
because the following code is not working (seems like a mock object is inserted, neither a DB interaction, neither a NullPointerException
comes up):
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTests {
@Spy
@Autowired
private UserRepository userRepository;
@Mock
private MessageService messageService;
@InjectMocks
private UserService userService = new UserServiceImpl();
@Test
public void testUserRegistration() {
userService.registerUser("[email protected]");
Assert.assertEquals("There is one user in the repository after the first registration.", 1, userRepository.count());
}
}
If I remove the @Spy annotation and insert the repository in the service with reflection, it works:
ReflectionTestUtils.setField(userService, "userRepository", userRepository);
This seems inconvenient, and I'm pretty sure that @Spy
is meant to do this. Can anyone point out what I'm missing/misunderstanding?
Edit: one more thing - with the @Spy
annotation I'm not getting a NullPointerException
on save, but it seems like a mock object is inserted instead of the real repository.
Edit 2: I think this is the answer for my confusion:
SpringBoot Junit bean autowire
Upvotes: 3
Views: 8879
Reputation: 51
The problem is that you probably @Autowired
some services/repositories in UserService
like these:
public class UserServiceImpl() {
@Autowired
private UserRepository userRepository;
@Autowired
private MessageService messageService;
// ... all the stuff
}
Mockito tries to inject mocks through constructor or setters which are not available. Try to redesign your class UserServiceImpl
, so it has constructor like:
public class UserServiceImpl() {
private final UserRepository userRepository;
private final MessageService messageService;
@Autowired
public UserServiceImpl(UserRepository userRepository, MessageService messageService) {
this.userRepository = userRepository;
this.messageService = messageService;
}
Then you can instantiate the service in @Before
with the constructor using those mocks.
Upvotes: 2