Spring Data's @EnableSpringDataWebSupport registers a couple of Spring MVC extensions that allow the easy consumption of Pageable and Sort instances as well as automatic identifier-to-entity conversion.
When running a test case with @WebMvcTest the auto-configuration that enables this is not activated, which I think is due to the fact that it sort of belongs to Spring Data. However, it fundamentally causes controller methods to behave differently.
I think it should be just fine to include SpringDataWebAutoConfiguration in the set of auto-configurations applied for @WebMvcTest as it doesn't strictly require any downstream Spring Data components but would make sure that mock repository beans would be picked up (so that the id-to-entity-conversion works during bean binding) and the Pageable and Sort resolution works.
Comment From: philwebb
@olivergierke I don't suppose you have an example test available anywhere that we could steal do you?
Comment From: habuma
@philwebb and @olivergierke : I threw together a little project at https://github.com/habuma/books-mvc-jpa that demonstrates the issue.
Put simply, when you run this app, requests to /books/1 and /books/2 work fine and the Book object passed into the bookDetail() method is looked up automatically from the BookRepository. But in the course of running the BooksControllerTest.bookDetail() test, it fails to convert the String path variable to the Book parameter that is annotated with @PathVariable.
Comment From: wilkinsona
Thank you, @habuma.
Comment From: wilkinsona
This isn't as simple as hoped as Spring Data's Web support is coupled to its repository infrastructure that isn't set up in a typical Web MVC test.
Using a mock CrudRepository, there's no RepositoryFactoryInformation in the application context. This means that the matches check inDomainClassConverter.ToEntityConverter<T> returns false as repositories.hasRepositoryFor(targetType.getType()) returns false.
@olivergierke What would you suggest? It looks like we'd need to do something to identify mocked Spring Data repositories in the context and somehow synthesise the RepositoryFactoryInformation for each of them.
Comment From: wilkinsona
Ping @olivergierke. We could do with some of your expertise here please.
Comment From: odrotbohm
Looks like getting DomainClassConverter to work without a bootstrapped repository infrastructure is kind of tricky. Here are the most apparent reasons:
- the invocation of whatever constitutes
findById(…)involves detailed knowledge of the production repository setup as in the no-mock case, we have to find out what object instance to actually invoke the method on. That's why the repository invoker infrastructure requires dependencies that we can't actually satisfy without the factories — and thus the entire infrastructure — to be present. - the
findById(…)method can be tweaked to use different wrapper types (Scala's or Vavr'sOption) - the
ToIdConverterneeds to lookup an entity's identifier which in case of some persistence providers might be a quite complex step (JPA's compound identifiers come to mind).
We can try to introduce an additional layer of abstraction between DomainClassConverter and the repository invoking infrastructure and see how far we can take it. I've filed this ticket to keep track of the efforts but I'd definitely vote for postponing this to after Spring Boot / Data 2.0.
Comment From: snicoll
There is another sample that demonstrates this with a very simple controller in #12938
Comment From: ideaplugins
I wrote this. That fixes my problem #12938. Let me know if it helps and I'll make a PR.
Comment From: wilkinsona
@ideaplugins If that change fixes your issue then it isn't the one being tracked by this issue. It looks like #12938 should possibly be reopened. What do you think, @snicoll?
Comment From: snicoll
@wilkinsona good catch, the scope of this issue has extended and we could do what @ideaplugins has done independently.
Comment From: wilkinsona
https://github.com/spring-projects/spring-data-commons/issues/1605 is the relevant Data Commons issue following the JIRA to GitHub issues migration. It remains open.