Mockito 无法创建 @Autowired Spring-Data Repository 的间谍

a-k*_*zer 12 java unit-testing spy spring-data-jpa spring-boot

我试图用 Mockito.spy 功能覆盖我的整个测试环境,所以无论何时我想要我都可以存根一个方法,但所有其他调用都转到默认功能。这在服务层上效果很好,但我在存储库层上遇到了问题。

我的设置如下:

Mockito - 2.15.0 Spring - 5.0.8 SpringBoot - 2.0.4

存储库:

public interface ARepository extends CrudRepository<ADBO, Long> {}
Run Code Online (Sandbox Code Playgroud)

服务:

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

间谍的配置:

@Profile("enableSpy")
@Configuration
public class SpyConfig {

    @Bean
    @Primary
    public ARepository aRepository() {
        return Mockito.spy(ARepository.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

还有我的测试课:

@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());

    }
}
Run Code Online (Sandbox Code Playgroud)

现在这个测试有三种可能的结果:

  • aRepository 既不是模拟也不是间谍:
    org.mockito.exceptions.misusing.NotAMockException: Argument passed to when() is not a mock! Example of corr...
  • aRepository 是模拟但不是间谍(这是我得到的结果):
    result (1):ADBO(id=null, testValue=null) result all:[]

  • aRepository 是一个间谍(这就是我想要的):
    result (1):ADBO(id=null, testValue=null) result all:[ADBO(id=1, testValue=bar)]

我将这种行为归因于存储库的 spring 实例化在后台更加复杂,并且在调用Mockito.spy(ARepository.class).

我还尝试将正确的实例自动装配到配置中并Mockito.spy()使用@Autowired 对象进行调用。

这导致:

Cannot mock/spy class com.sun.proxy.$Proxy75
Mockito cannot mock/spy because :
 - final class
Run Code Online (Sandbox Code Playgroud)

根据我的研究,自 v2.0.0 以来,Mockito 可以模拟和监视最终课程。

调用Mockito.mockingDetails(aRepository).isSpy()返回true让我认为后台的对象没有正确实例化。

最后我的问题:

如何使用@Autowired 在我的 UnitTest 中获取 Spring-Data Repository 的间谍实例?

小智 12

自 Spring Boot 版本2.5.3起, @SpyBean现在可以使用 Spring 数据存储库

如果您无法升级,您可以通过在测试方法主体中实例化您的间谍来解决此问题:

var yourSpy = Mockito.mock(FooRepository.class, AdditionalAnswers.delegatesTo(real))
Run Code Online (Sandbox Code Playgroud)


sno*_*lli 8

更新 08/2021

你应该使用@SpyBean.

它曾经被破坏(请参阅下面的问题链接),但自 Spring Boot 以来它已得到修复和支持2.5.3

如果您仍然遇到此错误并且无法更新您的 Spring Boot 版本,您可能想尝试解决此问题的答案之一@Mateusz Zaj?c 提出的解决方法。(如果对您有用,请考虑对他的回答进行投票)

链接到(已关闭)问题:http : //github.com/spring-projects/spring-boot/issues/7033