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

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

Related

#SpringBootTest loads unrequired Bean when making IT

I'm making some Integration Tests for my app and I'm encountering this problem I can't see how to solve.
I'm using Spring Boot 2.4.13 + Spring Data Neo4J 6.1.9
FYI, I deleted the Application default test that comes bundled when you create a project through Spring Initializr, and under /src/test/resources I have a .yml file named application.yml
My IT class looks like this:
#SpringBootTest
public class ClientIT {
#Autowired
private ClientServiceImpl service;
#Autowired
private ClientRepository repository;
#Test
void someTest() {
//Given
//When
//Then
}
}
But when I run this test I get the following Exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
And this is the cause:
Caused by: java.lang.IllegalStateException: The provided database selection provider differs from the ReactiveNeo4jClient's one.
The thing is I don't use SDN's Reactive features at all in my project. I don't even understand why Spring tries to load it. I've created an Issue under the Spring Data Neo4j GitHub repository (https://github.com/spring-projects/spring-data-neo4j/issues/2488) but they could only tell me that ReactiveNeo4jDataAutoConfiguration gets automatically included if there's a Driver or Flux class in the classpath which I don't have.
I've been debugging the Spring internals while booting up the Application after JUnit Jupiter methods to no success.
What I could see is that at some point after JUnit Jupiter tests preparation/initialization, "reactiveNeo4jTemplate" gets injected into DefaultListableBeanFactory's beanDefinitionNames variable.
I've tried many combinations of different annotations intended to be used when making Integration Tests but the one time it worked was after I explicitly excluded ReactiveNeo4jDataAutoConfiguration class through
#EnableAutoConfiguration(exclude=ReactiveNeo4jDataAutoConfiguration.class)
What I've always seen in some blogposts is that by using #SpringBootTest I shouldn't worry about this kind of problem but it looks like I need to add that annotation every time I want to make a new IT test.
My Integration Tests basically consist of bootstrapping the application + web server (tomcat) along with an embedded Neo4J instance and after that, making requests to check everything works as it should. Do I really need to worry about all of this just to make these simple tests?
Thank you
References:
How do I set up a Spring Data Neo4j integration test with JUnit 5 (in Kotlin)?
SprintBootTest - create only necessary beans
Answering my own question after finding what is causing this error:
In the linked Github Issue, one of the developers says having Flux.class in the classpath forces SDN to instantiate Neo4jReactiveDataAutoConfiguration which is what is causing the other reactive beans to instantiate.
Apparently, neo4j-harness brings io.projectreactor (where Flux.class belongs) as an indirect dependency through neo4j-fabric which is the root of our problems.
The Spring Data Neo4j will be fixing this issue in a patch later this week.

how to run springboot test without run tomcat?

I am developing a spring boot application and write some junit test.
But I find when I run any tests, tomcat is also started up, It makes those tests very slow and waste many times.
When I develop a SpringMvc application, junit test can run without start tomcat, It saves many times.
So, I want to ask it there anyway to run springboot test with out start tomcat?
Running a test with #SpringBootTest does not start an embedded server by default.
By default, it runs in the MOCK environment.
By default, #SpringBootTest will not start a server. You can use the
webEnvironment attribute of #SpringBootTest to further refine how your
tests run:
MOCK(Default) : Loads a web ApplicationContext and provides a mock web
environment. Embedded servers are not started when using this
annotation. If a web environment is not available on your classpath,
this mode transparently falls back to creating a regular non-web
ApplicationContext. It can be used in conjunction with
#AutoConfigureMockMvc or #AutoConfigureWebTestClient for mock-based
testing of your web application.
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
I guess what you wanted to achieve could be achieved by Slice Test concept. In general, you don't need a full-fledged mock environment or environment with an embedded server with all the configured beans in the spring container when you are performing unit tests.
For e.g. you have to unit test your Controller then you have #WebMvcTest annotation in place that will configure only web related beans and ignore the rest of the beans.
To test whether Spring MVC controllers are working as expected, use
the #WebMvcTest annotation. #WebMvcTest auto-configures the Spring MVC
infrastructure and limits scanned beans to #Controller,
#ControllerAdvice, #JsonComponent, Converter, GenericConverter,
Filter, WebMvcConfigurer, and HandlerMethodArgumentResolver. Regular
#Component beans are not scanned when using this annotation.
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests
Similarly, for the database layer, there is #DataJpaTest
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test
Long story short: when you intend to do unit testing with Spring framework, slice test is the one you should use in most of the cases.
If you are placing the following annotations, this will start the embedded container...
#RunWith(SpringRunner.class)
#SpringBootTest
Because, if you see the SpringBootTestContextBootstrapper.class class , this has been invoked the container which is invoked by #BootstrapWith(SpringBootTestContextBootstrapper.class) when we specify #SpringBootTest
You can remove those and can do as follows:
import org.junit.Test;
public class HellotomApplicationTests {
#Test
public void contextLoads() {
}
}
R-Click and RunAs Junit
O/P

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.

WebApplicationContext is always null in a spring boot test

My test class looks like this
#SpringBootTest(webEnvironment=WebEnvironment.MOCK)
public class sampleClassTest{
#Autowired
private WebApplicationContext wac;
}
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
In the setup method, wac is always null. From spring boot documentation, #SpringBootTest(webEnvironment=WebEnvironment.MOCK) always created a mock WebapplicaitonContext.
So I would expect it get autowired in the code above which doesn't happen.
Can someone tell me how to go about creating a webapplicationContext in this case so that it's not null like in my case ?
UPDATE
I am running spring boot tests invoking them from a class with springboot annotation.
Both test (springboottest) and calling class (springboot) application are in the same spring boot project under src/main/java.
I have nothing under src/main/test. I have done in this way because if classes from src/main/java want to call a test class then, it isn't really a test class.
Now, the problem is that I can't use runWith(SpringRunner.class) in springbootTest class. If I did that to get a mock webApplicationContext then, it gives me this error:
javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Admin,name=SpringApplication
I am not sure how to do about this.
To use #SpringBootTest you need to use Spring Framework's test runner. Annotate your test class with #RunWith(SpringRunner.class).
If someone is struggling with this issue in 2022 - please keep my defined precondions in mind. If you are using #SpringBootTest with defined port and constructor auto-wiring of the test class, the application context might be null.
It seems that the constructor dependency injection is eager and the cache aware context delegate of Spring is searching for a web application context which is no available yet. If you use field auto-wiring your test might run in a deterministic manner.
Whoever is facing this issue, make sure your spring boot starter parent version is compatible with spring cloud version in pom.xml
I was facing same issue, i resolved it by doing same.

WebServices, what to unit test?

I am developing a web application using Spring + Hibernate, plus CXF to convert my Service layer into a WebServices endpoint. I want to unit test my code, and when it comes to the DAOs I have no trouble: I create an in-memory database filled with my test data, then test DAOs against that.
But when testing the Service layer, most of my methods are like these:
#Override
#Transactional
public void saveProgramacion(ProgramacionDTO programacion) {
programacionDAO.persist(this.map(programacion, Programacion.class));
}
That is, my method just maps the VO to a DTO (using an external mapper) then calls a method of my DAO. Just that.
I used mockito to mock my DAO but honestly there are no instructions to provide mockito with since the service method itself does very little and does not check the DAO result. Given the fact that the mapper is an external dependency and thus would require its own unit test, what should I be testing here? What would be a proper unit test in this case?

Resources