Mock Spring Data Rest Repository

2.5k Views Asked by At

I faced with problem while testing data rest repositories. I call rest resource and check if it gets me proper json. But for pre-population data I don't want to use in memory db, so I mocked repository method invocation.
@MockBean private CommentRepository commentRepository; and did this

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

And now, while calling "/comments/1" I get 404 error, so data rest didn't expose my repository. The main question is "How can we mock repository method for getting data from database?"
My test class:

    @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
  }
}

As I understand, using MockBean annotation I replace current repository bean and it will not be exposed by data rest, Do we have any way to pre-populate data into db or mock invocation of repository method?

2

There are 2 best solutions below

0
On BEST ANSWER

I do not think this is possible. Spring data registers the repository beans using a FactoryBean - in the spring-data-rest case this is EntityRepositoryFactoryBean. So you cannot just override these beans with a mock.

For an interesting read on why mocking spring data repositories is not useful see this answer https://stackoverflow.com/a/23442457/5371736

In the same thread there is a reference to a project introducing mock support for spring-data repositories - https://stackoverflow.com/a/28643025/5371736

0
On

There is quick and dirty way to mock Spring Data Rest repositories with mockito, just in case somebody have no other options, but try to avoid this unless absolutely necessary

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