spring-boot #WebIntegrationTest is secured by default - spring

I'm relatively new to spring-boot and now I would like to write some integration tests for my first application.
My application provides several REST webservices, the main application starts like this
#EnableAutoConfiguration
#RestController
#SpringBootApplication
public class DistributorWebserviceApplication implements
ApplicationContextAware {..}
The application itself seems to be properly configured but in the integration test the webservice endpoints are secured and one needs username and password!? I didn't configure this on purpose.
Integration test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = DistributorWebserviceApplicationIntegrationTestConfiguration.class)
#WebIntegrationTest("server.port=0")
public class DistributorWebserviceApplicationIntegrationTest {..}
Spring configuration
#EnableAutoConfiguration
#Configuration
public class DistributorWebserviceApplicationIntegrationTestConfiguration {..}
Calling a webservice in a test method like
String url = String.format("http://localhost:%s%s", serverPort,
DistributorWebserviceApplication.URL_QUEUE_DISTRIBUTOR_JOB);
String result = restTemplate.postForObject(url, distributorJob,
String.class);
produces the result
{"timestamp":1431006031152,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/queueDistributorJob"}
Is there any possibility to disable the default security configuration?
Thank you in advance!

Related

How to connect to local running server in springboot testing

My application is running in local with port 8089, I am trying to do Spring Rest Controller testing.
It is running in 8089 port.
In application.yml
spring:
profiles:
active: sit
In application-sit.yml
server:
port: 8089
servlet:
context-path: /myapp
In My base test case:
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(SpringJUnit4ClassRunner.class)
//#SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
//#WebAppConfiguration
#SpringBootTest(classes = MyApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#ActiveProfiles("sit")
public abstract class FullOtpControllerTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
#Value("${server.port}")
int serverPort;
#Test
public void sendOtpTest() throws Exception {
String uri = "/sendOtp";
//{"clientId": "default2","tag": "tag","mobileNumber": "9999988888"}
SendOTPRequestDTO otpRequest = new SendOTPRequestDTO();
otpRequest.setClientId("default2");
otpRequest.setTag("tag");
otpRequest.setMobileNumber("9321901416");
String inputJson = mapToJson(otpRequest);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
//.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
String content = mvcResult.getResponse().getContentAsString();
assertEquals(8089,serverPort);
assertEquals(200, status);
}
}
But , first assert is passed. but in the debug it showing different port as showing in the below image.
I run: OtpControllerTest.sendOtpTest and I am getting:
java.lang.AssertionError:
Expected :200
Actual :404
MockMVC is intended for a different kind of testing.
It works in conjunction with #WebMvcTest annotation and allows testing your controller definitions: annotations, parameters, etc.
In this case spring starts a "splice" of the application that is relevant to the WEB layer, for example, it won't load beans annotated with #Service or #Repository, but will load all the #RestController annotated classes. If the controller depends on some service, you can mock it with a #MockBean annotation
In any case it doesn't require any kind of remote application everything runs "in-place".
#SpringBootTest annotation serves a different purpose, so you shouldn't run tests annotated with this annotation and use MockMVC instead:
#SpringBootTest runs the whole microservice (loads all the beans). Alternatively, there is a "mode" where spring boot test loads only explicitly defined Context Configurations...
If your purpose is black-box testing of the APIs of a remote application - you don't have to use spring at all - you don't need beans, don't need injection - you only need an Http Client of some sort (doesn't even have to be in Java) to implement this kind of tests.
One framework (out of many) is Rest Assured but again there are many choices here.

How to disable #Configuration initialization in WebFluxTest?

I would like to write tests for reactive controller using #WebFluxTest annotation, mocking all dependencies.
#WebFluxTest(controllers = MyController.class)
public class MyControllerTest {
#MockBean
SomeService service;
#Autowired
WebTestClient webClient;
//some tests
}
From what I understand, the WebFluxTest annotation shall apply only configuration relevant to WebFlux tests (i.e. #Controller, #ControllerAdvice, etc.), but not another beans.
My spring boot app contains a number of #Configuration classes that configure a number of beans (annotated as #Bean). Some of those configurations have also dependencies (autowired by constructor).
#Configuration
#RequiredArgsConstructor
public class MyConfig {
private final AnotherConfig anotherConfig;
#Bean
//...
}
When I run my web flux tests, I can see the context initialization contains an attempt to initialize the MyConfig (and it fails because of the missing dependency which comes from 3rd party auto-configured lib). How can I configure the test to skip initialization of all of these?
I am able to exclude the problematic configuration class only by excluding auto configuration of the whole app.
#WebFluxTest(controllers = MyController.class, excludeAutoConfiguration = {MyApplication.class})
public class MyControllerTest { ... }
where MyApplication is the spring boot app autoscanning those configuration classes.
But how can I achieve to skip initialization of MyConfig only? Or even better, how can I achieve to only include a list of configurations to be initialized?
Add
#ActiveProfiles("YOUR_ENV_OTHER_THAN_TEST")
below or above #Configuration
For multiple environments..
#ActiveProfiles(profiles ={env1, env2,env3})

Spring-boot application-test.properties

I am trying to unit test the spring-boot application using junit. I have placed the application-test.properties under src/test/resources. I have a ApplicationConfiguration Class which reads the application.properties.
My test class looks like this
#RunWith(SpringRunner.class)
#SpringBootTest(classes=ApplicationConfiguration.class)
#TestPropertySource(locations = "classpath:application-test.properties")
#ActiveProfiles("test")
public class TestBuilders {
#Autowired
private ApplicationConfiguration properties;
When I try to read the properties, it is always null.
My ApplicationConfiguration Class looks something like this
#Configuration
#ConfigurationProperties
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource(value="file:config.properties", ignoreResourceNotFound =
true)})
public class ApplicationConfiguration{
private xxxxx;
private yyyyy;
I tried all possible ways that I found on google.. No luck. Please help!
Thanks in Advance.
The issue is you don't have #EnableConfigurationProperties on your test class.
When you load the application it start from main class(one which has #SpringBootApplication) where you might have #EnableConfigurationProperties and hence it works when you start the application.
Whereas when you are running the Test with only ApplicationConfiguration class as you have specified here
#SpringBootTest(classes=ApplicationConfiguration.class)
Spring doesn't know that it has to Enable Configuration Properties and hence the fields are not injecting and hence null. But spring is reading your application-test.properties file. This can be confirmed by just injecting the value directly in your test class
#Value("${xxxxx}")
private String xxxxx;
Here the value is injected. But to inject into a class with ConfigurationProperties you need to enable it using #EnableConfigurationProperties
Put #EnableConfigurationProperties on your test class and everythhing works fine.

Does #WebMvcTest require #SpringBootApplication annotation?

My goal is to migrate a Spring Boot application previously developed with Spring Boot 1.3 to the newest Spring Boot version 1.4. The application consists of several maven modules and only one of them contains class annotated with #SpringBootApplication.
One part of migration is to use #WebMvcTest annotation to efficiently test controllers, and here I get an issue.
Consider an example application from Spring Boot github page. #WebMvcTest annotation works perfectly, because, as far as I understand (after I did several tests), there is a class in the main package annotated with #SpringBootApplication. Note that I follow the same concept as shown in the example above for my own #WebMvcTest tests.
The only difference I see that in my application, controller classes are located in a separate maven module (without #SpringBootApplication annotated class), but with #Configuration and SpringBootConfiguration configurations. If I do not annotate any class with #SpringBootApplication I always get an assertion while testing controller. My assertion is the same as when SampleTestApplication class in the example above modified to have only #EnableAutoConfiguration and #SpringBootConfiguration annotations (#SpringBootApplication is not present):
getVehicleWhenRequestingTextShouldReturnMakeAndModel(sample.test.web.UserVehicleControllerTests) Time elapsed: 0.013 sec <<< FAILURE!
java.lang.AssertionError: Status expected:<200> but was:<404>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:664)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at sample.test.web.UserVehicleControllerTests.getVehicleWhenRequestingTextShouldReturnMakeAndModel(UserVehicleControllerTests.java:68)
How should I deal with that? Should I always have class annotated with #SpringBootApplication in order to run #WebMvcTest tests?
EDIT 1: I did a small maven project with 2 modules and a minimal configuration. It is here. Now, I get NoSuchBeanDefinitionException exception for repository defined in another module. If I configure "full" #SpringBootApplication - everything is fine.
EDIT 2: I modified small test project from EDIT 1 to give an original issue. I was playing with different annotations and added #ComponentScan on configuration class, because I suspected that beans are not registered properly. However, I expect that only #Controller bean (defined in #WebMvcTest(...class)) shall be registered based on magic behind #WebMvcTest behaviour.
EDIT 3: Spring Boot project issue.
Short answer: I believe so.
Long answer:
I believe #WebMvcTest needs to find the SpringBootApplication configuration since WebMvcTest's sole purpose is to help simplify tests (SpringBootApplication would rather try to load the whole world).
In your specific case, since you don't have any in your non-test packages, I believe it also finds SampleTestConfiguration which is annotated with #ScanPackages and somehow loads every beans.
Add the following in src/main/java/sample/test
#SpringBootApplication
public class SampleTestConfiguration {
}
And change your test to this:
#RunWith(SpringRunner.class)
#WebMvcTest(MyController.class)
public class MyControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private MyService ms;
#Autowired
private ApplicationContext context;
#Test
public void getDataAndExpectOkStatus() throws Exception {
given(ms.execute("1")).willReturn(false);
mvc.perform(get("/1/data").accept(MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isOk()).andExpect(content().string("false"));
}
#Test
public void testMyControllerInAppCtx() {
assertThat(context.getBean(MyController.class), is(not(nullValue())));
}
#Test
public void testNoMyAnotherControllerInAppCtx() {
try {
context.getBean(MyAnotherController.class);
fail("Bean exists");
} catch (BeansException e) {
// ok
}
}
}
#WebMvcTest finds the SpringBootApplication, then load only a limited number of beans (see documentation):
#WebMvcTest will auto-configure the Spring MVC infrastructure and
limit scanned beans to #Controller, #ControllerAdvice, #JsonComponent,
Filter, WebMvcConfigurer and HandlerMethodArgumentResolver. Regular
#Component beans will not be scanned when using this annotation.
WebMvcTest requires SpringBootApplication: WebMvcTest inherits many AutoConfiguration, so it needs SpringBoot to load them. Then it disables many other AutoConfiguration and your Controllers become easily testable.
The whole point of using WebMvcTest is when you have a SpringBootApplication and you wish to make it simpler to test by disabling all beans except Controllers. If you don't have SpringBootApplication, then why use WebMvcTest at all?
It's an old topic, but there is a solution which wasn't mentioned here.
You can create a class annotated with SpringBootApplication just in your test sources. Then, you still have a nice, multi-module structure of your project, with just one "real" SpringBootApplication.
Yes,according to the spring boot docs
The search algorithm works up from the package that contains the test until it finds a #SpringBootApplication or #SpringBootConfiguration annotated class. As long as you’ve structure your code in a sensible way your main configuration is usually found.
But after I started using #WebMvcTest,spring boot still try to load other beans, finally TypeExcludeFilter did the trick.
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = {JzYsController.class} )
public class JzYsControllerTest {
private static final String REST_V4_JZYS = "/rest/v4/JzYs";
#Autowired
private MockMvc mockMvc;
#MockBean
private JzYsService service;
#Test
public void deleteYsByMlbh() throws Exception {
Mockito.when(service.deleteYsByMlbh(Mockito.anyString())).thenReturn(Optional.of(1));
mockMvc.perform(delete(REST_V4_JZYS + "?mbbh=861FA4B0E40F5C7FECAF09C150BF3B01"))
.andExpect(status().isNoContent());
}
#SpringBootConfiguration
#ComponentScan(excludeFilters = #Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public static class config{
}
}
There is one more solution. You can not use #WebMvcTest, but configure MockMvc yourself through the builder
class TestControllerTest {
private MockMvc mvc;
#BeforeEach
public void setup() {
mvc = MockMvcBuilders.standaloneSetup(new TestController())
.build();
}
#Test
void test() throws Exception {
// When
var res = mvc.perform(MockMvcRequestBuilders.get("/test/test"));
// Then
res.andExpect(status().isOk());
}
}
But this solution may entail a number of other problems, such as problems with configurations, environment property injections, etc.

Spring Boot MockMVC Test does not load Yaml file

I have my configuration in application.yml file in the root of classpath (src/main/resources/). The configuration gets loaded fine when I start the application normally. However in my test the application.yml file gets not loaded at all.
The header of my test looks as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = Configuration.class)
#org.junit.Ignore
public class ApplicationIntegrationTest {
#Inject
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
...
The configuration class:
#EnableAutoConfiguration
#ComponentScan("c.e.t.s.web, c.e.t.s.service")
public class Configuration extends WebMvcConfigurerAdapter {
When I debug the application I see that the yml files get loaded in ConfigFileApplicationListener, in the test however the ConfigFileApplicationListener gets not called.
There is a whole chapter in the Spring Boot Reference guide regarding testing. This section explains how to do a basic test for a Spring Boot application.
In short when using Spring Boot and you want to do a test you need to use the # SpringApplicationConfiguration annotation instead of the #ContextConfiguration annotation. The #SpringApplicationConfiguration is a specialized #ContextConfiguration extension which registers/bootstraps some of the Spring Boot magic for test cases as well.
There is a good integration between StringBoot, jUnit and YAML.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(MainBootApplication.class)
public class MyJUnitTests {
...
}
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "section1")
public class BeanWithPropertiesFromYML {
...
}
For more details please check my comment here: https://stackoverflow.com/a/37270778/3634283

Resources