I am trying to overlay my whole test environment with Mockito.spy functionality so whenever I want i can stub a method but all other calls go to default functionality. This worked very well with the Service layer but I have problems with the Repository layer.
My setup is as follows:
Mockito - 2.15.0 Spring - 5.0.8 SpringBoot - 2.0.4
Repository:
public interface ARepository extends CrudRepository<ADBO, Long> {}
Service:
@Service
public class AService {
@Autowired
ARepository aRepository;
public ADBO getById(long id) {
return aRepository.findById(id).orElse(null);
}
public Iterable<ADBO> getAll() {
return aRepository.findAll();
}
}
The configuration for the spy:
@Profile("enableSpy")
@Configuration
public class SpyConfig {
@Bean
@Primary
public ARepository aRepository() {
return Mockito.spy(ARepository.class);
}
}
And my test class:
@ActiveProfiles("enableSpy")
@RunWith(SpringRunner.class)
@SpringBootTest
public class AServiceTest {
@Autowired
AService aService;
@Autowired
ARepository aRepository;
@Test
public void test() {
ADBO foo = new ADBO();
foo.setTestValue("bar");
aRepository.save(foo);
doReturn(Optional.of(new ADBO())).when(aRepository).findById(1L);
System.out.println("result (1):" + aService.getById(1));
System.out.println("result all:" + aService.getAll());
}
}
Now there are three possible outcomes to this test:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of corr...
aRepository is a mock but not a spy (this is the result I get):result (1):ADBO(id=null, testValue=null)
result all:[]
aRepository is a spy (this is what I want):result (1):ADBO(id=null, testValue=null)
result all:[ADBO(id=1, testValue=bar)]
I attribute this behavior to the fact that the spring instantiation of the repository is more complex in the background and the repository is not correctly instantiated when calling Mockito.spy(ARepository.class)
.
I have also tried autowireing the proper instance into the Configuration and calling Mockito.spy()
with the @Autowired object.
This results in:
Cannot mock/spy class com.sun.proxy.$Proxy75
Mockito cannot mock/spy because :
- final class
According to my research Mockito can mock and spy final classes since v2.0.0.
Calling Mockito.mockingDetails(aRepository).isSpy()
returns true
which leads me to think the object in the background was not correctly instantiated.
Finally my question:
How do I get a spy instance of a Spring-Data Repository in my UnitTest with @Autowired?
You should use @SpyBean
from spring-boot-test
.
This used to be broken (per Spring Boot issue #7033) but it's now been fixed and supported since Spring Boot 2.5.3
.
If you still getting this error and can't update your Spring Boot version, you might want to try the work-around proposed by @Mateusz Zając in his answer to this question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With