For all I know, MockMvc is just testing the Controller, and mocking the Service layer.
Whilst RestAssured and TestRestTemplate are testing the running instance of our API.
Is that correct?
And what's the difference between RestAssured and Spring Boot's TestRestTemplate?
MockMvc is one of the classes in spring-test. This is primarily used for unit testing of the controller layer. Not just your controller class. This is for tetsing the controller layer. But you have to mock service and other layers. Hence it is primarily used for unit testing.
TestRestTemplate is again part of spring test, as the documentation says,
Convenient alternative of {#link RestTemplate} that is suitable for
integration tests.
This can be used to test your Rest Service/ endpoints. One of the main difference is you use MockMvc for unit testing and TestRestTemplate for Integration testing. In other words, for using MockMvc, you don't need a running instance of server, but for TestRestTemplate you would need.
RestAssured is a completely different framework. This has nothing to do with Spring. This is a librariy, which provides various ways to test any REST service with fluent BDD style interface.
As mentioned MockMvc is used to mock the service layer. It is useful in unit-testing of the code.
Whereas both RestAssured and TestRestTemplate are used for integration-testing which is end to end APIs testing.
Also, there is not much difference between RestAssured and Spring Boot's TestRestTemplate. You can use RestAssured for Spring-Boot Application or can go ahead with TestRestTemplate which is a Spring library.
MockMvc is primarily used for web layer testing. Web layer testing is essentially writing fine-grained tests specifically designed to test your app’s controllers. It is very similar to writing regular unit tests for classes where you need mock dependencies for testing specific methods.
As far as comparing RestAssured vs TestRestTemplate they do pretty much the same thing. When it comes to RESTful based API integration testing and validation, TestRestTemplate and RestAssured both offer convenient methods to create and execute your HTTP calls with custom headers, auth, content types, query parameters, payload content, cookies, etc. The main difference -aside from syntax- is that TestRestTemplate is part of Spring’s test framework which comes bundled with the spring-boot-starter-test dependency.
Check out this article - Testing Spring Boot RESTful APIs using MockMvc/Mockito, Test RestTemplate and RestAssured - it has additional explanation and robust examples on the usage for all three (MockMvc, TestRestTemplate, and RestAssured).
Related
I'm trying to write a integration test for my SpringBoot microservice that interacts with another service inside the product ecosystem.
Since this kind of testing is consider function/integration testing (depending on what nomenclature you use) it is usually done on some development environment.
However, I wanted to test a basic interaction between my service and a STUB/dummy app which are connected with RPC (so not exactly a typical TestRestTemplate test).
I know that there is a way to embed a service while booting up the Spring Context but have never done it by myself.
Does anyone have any experience with the upper or maybe a few helpful links where I can explore.
I have used WireMock in tests to mock services external to what I want to test that communicate over HTTP.
My test class annotated with #SpringBootTest is also annotated with #ContextConfiguration. In the classes attribute #ContextConfiguration I explicitly specify the configuration classes required to set up the Spring Context for the test in question. Here I can also include additional configuration classes in which I create beans only used in the test. In test configuration classes I can also override beans for the purpose of the test, creating mock beans etc.
Note that Spring Boot 2.1 and later disables bean overriding by default. It can be enabled by setting the following property to true:
spring.main.allow-bean-definition-overriding=true
To set the property for a single test, use the #TestPropertySource annotation like this:
#TestPropertySource(properties = {
"spring.main.allow-bean-definition-overriding=true"
})
I am trying to Unit Test a Spring MVC Controller. But don’t know how to do it. So can anyone tell me how to Unit Test a Spring Web MVC Controller using JMockit
Use Spring MockMvc to write unit test cases for controller.
Refer https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/web/servlet/MockMvc.html
Spring Boot 1.4 introduces #AutoConfigureRestDocs (See http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs). The docs state:
It will automatically configure MockMvc to use Spring REST Docs and remove the need for Spring REST Docs' JUnit rule.
I would like to use the restassured support of Spring REST Docs instead of mockmvc. Can I do this with #AutoConfigureRestDocs ?
No, not at the moment. #AutoConfigureRestDocs builds on top of Spring Boot's testing support being able to auto-configure MockMvc. There's no support for auto-configuring REST Assured which the REST Docs auto-configuration could then build upon. If it's something that you'd like to see in Spring Boot, please open an enhancement request.
Conext
I found this question here but my problem is different.
So we are using Katharsis Controller and Spring Data Rest.
We only have 1 controller for entire application and then the request will be sent to Spring Data Rest repositories classes.
We want to use Spring Restdoc to generate documentation which requires us to write unit tests with MockMvc.
But when using Mockmvc, it starts up the container and will require datasources to be set up.
If we use standaloneSetup() and pass the mocked repository class, then MockMvc won't load Katharsis Controller and therefore the request won't reach that repository.
I understand that we can create an in-memory database but our project is big and the database needs a huge number of tables to be created we want to avoid that since these tests are for documentation purposes.
Question
Is there any way to achieve this and only mock the target repository class?
Note
By repository I mean CrudRepository interface in Spring DataRest.
As Andy Wilkinson suggested, you may consider creating unit test where you wire beans together by yourself and use MokMvc standalone setup.
If you want to create integration test and create Spring Context anyway, there is way to fake Spring bean by using #Primary, #ActiveProfiles and #Profile annotations. I wrote a blog post with GitHub example how to do it. You just need to combine this approach with WebApplicationContext based MockMvc setup. It works without problems, I wrote such tests in the past.
I'm trying to perform a POST request on URL outside the current context, and it looks like Spring cannot understand it.
Test code:
String content = mvc
.perform(post("http://some-external-url.com:8080/somepath)
.header("Authorization", authorization)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("username", username)
.param("password", password)
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
Works like a charm on current context. But remote service cannot be reached at all. It seems like "http://some-external-url.com:8080" part is ignored.
Mock creation code:
mvc = MockMvcBuilders.webAppContextSetup(context).build();
Is there any way to make it work? Because using standard Java HttpUrlConnection class is a huge pain.
No. There is no way to make the Spring MVC Test Framework work with external servers (or any actual server for that matter).
As stated in the Spring Reference Manual,
The Spring MVC Test framework provides first class support for testing
Spring MVC code using a fluent API that can be used with JUnit,
TestNG, or any other testing framework. It’s built on the Servlet API
mock objects from the spring-test module and hence does not use a
running Servlet container.
The last sentence spells it out: Spring MVC Test does not use a running Servlet container. In fact, it cannot be used with a running Servlet container or any kind of actual server (local or remote).
As an alternative, if you must test against an external server, you could then consider using REST Assured instead of Spring MVC Test for those special cases.
You can use new RestTemplate().getForObject("http://some-external-url.com:8080/somepath", String.class)