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

时间:2018-08-09 09:44:55

标签: java unit-testing spring-boot spring-data-jpa spy

我正在尝试使用Mockito.spy功能覆盖整个测试环境,以便在我需要的时候可以对方法进行存根,但所有其他调用均转为默认功能。 这在Service层上效果很好,但是我在Repository层上遇到了问题。

我的设置如下:

Mockito-2.15.0 春季-5.0.8 SpringBoot-2.0.4

存储库:

public interface ARepository extends CrudRepository<ADBO, Long> {}

服务:

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

间谍的配置:

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

    @Bean
    @Primary
    public ARepository aRepository() {
        return Mockito.spy(ARepository.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());

    }
}

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

  • 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)]

我将此行为归因于以下事实:存储库的春季实例化在后台更加复杂,并且在调用Mockito.spy(ARepository.class)时没有正确地实例化存储库。

我还尝试将适当的实例自动连接到Configuration中,并使用@Autowired对象调用Mockito.spy()

结果是:

Cannot mock/spy class com.sun.proxy.$Proxy75
Mockito cannot mock/spy because :
 - final class

根据我的研究,自2.0.0版以来,Mockito可以模拟和监视最终类。

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

最后我的问题:

如何通过@Autowired在我的UnitTest中获取一个Spring-Data Repository的间谍实例?

2 个答案:

答案 0 :(得分:0)

您应该使用@SpyBean,但很遗憾它已损坏并且不适用于spring数据存储库

链接到问题: http://github.com/spring-projects/spring-boot/issues/7033

答案 1 :(得分:0)

@SpyBean 现在 使用 Spring 数据存储库,因为 Spring Boot 版本 2.5.3

如果你不能升级,你可以通过在测试方法主体中实例化你的间谍来解决这个问题:

<div v-for="file in files" :key="file.id"></div>

data() {
  return {
    soundFiles: [ array of your files ],
  }
},
computed: {
  files() {
    return soundFiles.map(x => {
      x.id = Math.floor(Math.random() * 1000000000)
      return x;
    })
  }
}