How to mock rest client inside a Spring boot integration test - spring-boot

In a spring boot integration test annotated with #SpringBootTest and ran with #RunWith(SpringRunner.class) I can drop real http post calls to my rest controller via #Autowired TestRestTemplate restTemplate and restTemplate.postForEntity(...)
This works fine, just at the end of the controller -> service -> restclient chain I have a rest client bean, which is calling a 3rd party rest endpoint using RestTemplates inside, so I have to mock this endpoint. I found this lib com.github.tomakehurst.wiremock.client.WireMock, which can be used for this, but was wondering whether there is not a nice spring boot way like for example the way to test a rest client with #RestClientTestto achieve this. I tried to mock the MockRestServiceServer so that I can write expectations and responses on it, but it does not seem to get it. The rest templates inside my rest client are always created as real, thus my call to the 3rd party endpoint fails.

You can inject the mock in the #Before using ReflectionTestUtils
#Inject
private Service service;
#Mock
private RestClient restClient;
#Before
public void setup() {
ReflectionTestUtils.setField(service, "restClient", restClient);
}

Related

Spring tests shutting down standalone wiremock server

I have some end-to-end UI tests with WebDriver that use a remote wiremock instance, that I connect to in the following way:
#Configuration
public class WireMockConfiguration {
#Bean
public WireMock wireMock() {
return new WireMock("my-pyroxy.corp", 8080);
}
}
I have noticed that after tests finish, the wiremock server receives a shutdown request. The Wiremock::shutdown method is not marked with any annotation like #PreDestroy but Spring is still invoking it.
How do I stop it (apart from creating this wiremock client bean outside of the spring context?)
From the documentation of #Bean, I have learned this
To disable destroy method inference for a particular #Bean, specify an empty string as the value, e.g. #Bean(destroyMethod="")

How to set response date format in rest assured mock mvc while testing spring could contract for a web service?

I am using tests generated by spring cloud contracts to test web service response.
The service used to return date as timestamp, now with the updated Spring version (2.0.5) dates are returned in the "2018-11-30T21:16:18.220+0000" format. The contract tests are still passing without any change. I learned that this is because Spring could contract uses RestAssuredMockMvc which is unaware of springs application configs. How can I change the config in the contracts to make sure that contracts always check for the date in same format as that are correctly returned by the service?
For Spring Boot application, simple way to execute RestAssured against spring application setup is:
#RunWith(SpringRunner.class)
#WebMvcTest
// or #SpringBootTest
public abstract class BaseContractTest {
#Autowired
protected MockMvc mockMvc;
#Before
public void setup() {
RestAssuredMockMvc.mockMvc(mockMvc);
}
}
Version with #WebTestClient runs faster but needs mocking services, version with #SpringBootTest runs slower but utilize whole application.
Proposed in previous answer RestAssuredMockMvc.webAppContextSetup() is very similar to version with #SpringBootTest. The second proposition, RestAssuredMockMvc.standaloneSetup(), requires a complicated configuration, different than Spring application configuration.
For that reason RestAssuredMockMvc.standaloneSetup() is error prone and worse than #WebMvcTest.
RestAssuredMockMvc.webAppContextSetup() is OK
Try this.
Setup object mapper with RestAssuredMockMvc.standaloneSetup
RestAssuredMockMvc.standaloneSetup(
MockMvcBuilders
.standaloneSetup(yourcontroller).setMessageConverters(mappingJackson2HttpMessageConverter)
);
Either add the missing configuration to the mockmvc rest assured setup or use explicit mode of tests generation and setup a real spring boot context

Integration testing with spring declarative caching

I'm trying to write integration tests for a Spring Boot 2 Application.
One test should test updating a value via REST.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureTestEntityManager
#Transactional
public class TenantEndpointIT {
#Autowired
private TestRestTemplate template;
#Autowired
private TestEntityManager entityManager;
#Test
public void nok_updateValueForbidden() {
}
}
Now, I thought the cleanest way was to create the value with the TestEntityManager in the #Before method, then test the REST endpoint in the actual test.
But the service called by the REST Endpoint is annotated with Spring Caching annotations. So the test fails if I do that. I could use the service directly or make a second REST call. That creates problems with other tests using the same Value, because even if the DB is rolled-back, the cache seems to contain the value. (Now I'm using #DirtiesContext).
My question is, how do you correctly integration test services with #Cachable?
Is there a way to get the Cache and explicitly put/remove?
I tried autowiring a CacheManager, but it won't find one and fails.
If you add #AutoConfigureCache on your test, it will override whatever cache strategies you've defined in your app by a CacheManager that noops. That's pretty useful if you want to make sure that cache doesn't interfere with your tests.

Spring Boot Test - Mocking A Handler Bean That Is Placed Deep In The Chain Of Responsibility

This should happen quite often:
RestController -> SomeClass -> SomeOtherClass -> YetAnotherClass and so on...
In my specific case there is a chain of responsibility which is injected to a rest controller. Each class is injected to it's previous class in the above chain.
I have implemented this with spring boot and I'm trying to test the REST resource. I want to Mock the "YetAnotherClass" so that when I send a request with MockMvc I can verify that something has happened in the mock object.
The problem is if I use #MockBean to mock YetAnotherClass then I have to inject it to SomeOtherClass. I have tried to inject it with #TestConfiguration but it seems that the Mock object injection doesn't work this way when the request is sent through MockMvc and the mock object is nested deep inside a chain such as above. (The original bean is injected not the mock one)
I know that JMockit mocks every instance of a class so it would solve my problem. But Spring boot defaults to Mockito and I prefer to avoid inconsistencies.
How can I implement such a test scenario?
I've run into a lot of annoyance using Mockito's annotation config setup when setting up Spring JUnit text fixtures.
I've found the way I like mocking beans with external integrations like this this by essentially having a separate MockObjectsConfig class with the mock objects I want using the standard Spring Context Configuration, and then import it alongside my real test config:
#Configuration
public class MockObjectsConfig {
#Bean
public YetAnotherClass yetAnotherClass() {
Mockito.mock(YetAnotherClass.class); // and add any thenReturns, answers, etc. here
}
... More mock beans...
}
Then include it in your test like so:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { MyRealConfigClass.class, MockObjectsConfig.class)
public class MyJunitTest {
#Autowired
private RestController restController;
}
You can also annotate your mock bean with #Profile and test with #ActiveProfiles if you need to prevent a conflict there.
This way your mock YetAnotherClass will get injected into your context like all your other beans -- no relying on, mixing, and fiddling around with Mockito and other library annotations.

Can we use org.springframework.ws.server.endpoint.annotation.Endpoint annotated class to create RESTful web service with Spring

I have to create RESTful web service in an existing application which currently provides SOAP services and thus uses org.springframework.ws.server.endpoint.annotation.Endpoint, so could I use #Endpoint annotated class instead of #RestController to create RESTful web service with Spring and can these classes have following method:
#RequestMapping(value = "/myMethod", method=RequestMethod.GET)
public ResponseEntity<String> restMethod() {
...
}
#Endpoint annotation mark a class as a SOAP endpoint, which will handle through its methods SOAP requests. Whereas #RestController, according to it javadoc, is "a convenience annotation that is itself annotated with #Controller and #ResponseBody", that is a very convenient mechanism to create REST services. So you can not use #Endpoint waiting for it to behave like #RestController.

Resources