模拟 Spring Data Rest 存储库

Posted

技术标签:

【中文标题】模拟 Spring Data Rest 存储库【英文标题】:Mock Spring Data Rest Repository 【发布时间】:2017-04-30 10:48:59 【问题描述】:

我在测试数据存储库时遇到了问题。我打电话给休息资源并检查它是否让我得到正确的json。但是对于我不想在内存数据库中使用的预填充数据,所以我模拟了存储库方法调用。@MockBean private CommentRepository commentRepository; 并做到了这一点

given(commentRepository.findOne(1L)).willReturn(comment);

现在,在调用“/cmets/1”时,我得到 404 错误,所以数据休息没有暴露我的存储库。主要问题是“我们如何模拟从数据库获取数据的存储库方法?” 我的测试课:

    @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CommentTest

  @Autowired
  private TestRestTemplate restTemplate;

  @MockBean
  private CommentRepository commentRepository;

  @Before
  public void setup()
  
    Comment comment = new Comment();
    comment.setText("description");
    comment.setCommentId(1L);

    given(commentRepository.findOne(1L)).willReturn(comment);
  

  @Test
  public void shouldCheckCommentGetResource()
  
    ParameterizedTypeReference<Resource<Comment>> responseType = new ParameterizedTypeReference<Resource<Comment>>() ;

    ResponseEntity<Resource<Comment>> responseEntity =
        restTemplate.exchange("/comments/1", HttpMethod.GET, null, responseType, Collections
            .emptyMap());

    Comment actualResult = responseEntity.getBody().getContent();
    assertEquals("description", actualResult.getText());
    // more assertions
  

据我了解,使用 MockBean 注释我替换了当前存储库 bean,它不会被数据休息暴露,我们有没有办法将数据预填充到 db 或模拟调用存储库方法?

【问题讨论】:

你能给我们看看你的测试和豆子吗? 【参考方案1】:

有一种快速而肮脏的方法可以用 mockito 模拟 Spring Data Rest 存储库,以防万一有人没有其他选择,但除非绝对必要,否则尽量避免这种情况

class MockRestRepositoryUtil 
    public static <T> T mockRepository(Class<T> repositoryClass,
                                        T springRepository) throws Exception 
        Object springRepositoryImpl = AopTestUtils.getTargetObject(springRepository);
        T mockRepository = mock(repositoryClass, delegatesTo(springRepositoryImpl));
        Object springProxyHandler = Proxy.getInvocationHandler(springRepository);
        ProxyFactory proxyFactory = extractProxyFactory(springProxyHandler);
        proxyFactory.setTarget(mockRepository);
        removeSpringDataAspects(proxyFactory);
        return mockRepository;
    

    private static ProxyFactory extractProxyFactory(Object springProxyHandler) throws Exception 
        Field advisedField = springProxyHandler.getClass().getDeclaredField("advised");
        advisedField.setAccessible(true);
        return (ProxyFactory) advisedField.get(springProxyHandler);
    

    private static void removeSpringDataAspects(ProxyFactory proxyFactory) 
        Advisor[] advisors = proxyFactory.getAdvisors();
        Arrays.stream(advisors)
            .filter(advisor -> advisor.getAdvice().getClass().getPackage().getName()
                .contains("org.springframework.data"))
            .collect(toImmutableList())
            .forEach(proxyFactory::removeAdvisor);
    

【讨论】:

【参考方案2】:

我认为这是不可能的。 Spring data 使用 FactoryBean 注册存储库 bean - 在 spring-data-rest 情况下,这是EntityRepositoryFactoryBean。因此,您不能只用模拟覆盖这些 bean。

有关为什么模拟 Spring 数据存储库没有用的有趣读物,请参阅此答案https://***.com/a/23442457/5371736

在同一个线程中,引用了一个引入对 spring-data 存储库的模拟支持的项目 - https://***.com/a/28643025/5371736

【讨论】:

以上是关于模拟 Spring Data Rest 存储库的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data Rest 中同一实体的多个存储库

如何禁用 Spring Data REST 存储库的默认公开?

Spring Data REST:覆盖控制器上的存储库方法

Spring Data REST 是不是支持响应式 crud 存储库?

Spring Boot MongoDB REST - 自定义存储库方法

使用 Spring Data MongoDB 的 Rest API - 存储库方法不起作用