I am trying to write junit for the controller class which is written using spring webflux.
#ExtendWith(SpringExtension.class)
#WebFluxTest(SecurityApiHandler.class)
#ContextConfiguration(classes = { SecurityApiRouter.class, SecurityApiHandler.class })
public class SecurityApiHandlerTest {
#Autowired
private static ApplicationContext context;
private static WebTestClient webTestClient;
#MockBean
private SecurityApiService securityService;
#BeforeAll
public static void setUp() {
webTestClient = WebTestClient.bindToApplicationContext(context).build();
}
#Test
public void healthCheckTest() {
webTestClient.get().uri("/health-check").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk()
.expectBody(HealthCheck.class).value(response -> {
Assertions.assertThat(response.getApiName()).isEqualTo("security-service");
});
}
}
I am following this article to write my test case: https://blog.knoldus.com/spring-webflux-testing-your-router-functions-with-webtestclient/
ApplicationContext is not getting autowired due to which I am getting error IllegalArgumentException: ApplicationContext is required
Related
Can someone point me to what could be wrong in below code. It is a boot spring 2.6.7 application. When test profile is running, it throws error for all tests like below.
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used
#AutoConfigureMockMvc
#SpringBootTest(classes = some.class)
#ActiveProfiles("test")
public class someTest {
#Autowired
private MockMvc mvc;
#Autowired
private WebApplicationContext webAppContext;
#MockBean
private SomeBean someBean;
#SpyBean
private SomeSpyBean someSpyBean;
#BeforeEach
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(webAppContext)
.apply(springSecurity())
.build();
}
#Test
public void SomeTest1() throws Exception {
String text = "text1";
when(someBean.findStuff(text).thenReturn(Optional.of(new Thingie()));
mvc.perform(multipart("/api/somepath/")
.andExpect(status().isNotFound());
verify(someSpyBean).doStuff();
}
#Test
public void SomeTest2() throws Exception {
String text = "text2";
when(someBean.findStuff(text).thenReturn(Optional.of(new Thingie()));
mvc.perform(multipart("/api/somepath/")
.andExpect(status().isFound());
verify(someSpyBean).doStuff();
}
}
I want to use WebTestClient in my tests. works like this:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureWebTestClient
public class ControllerTest {
#Autowired
private WebTestClient webTestClient;
#Test
public void webtestClient () {
assertNotNull(webTestClient);
}
}
But now I want to inject WebTestClient into a helper class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureWebTestClient
public class ControllerTest {
#Autowired
private Helper helper;
#Test
public void webtestClient () {
helper.check();
}
}
#Component
public class Helper {
#Autowired
private WebTestClient webTestClient;
public void check() {
assertNotNull(webTestClient);
}
}
Works, too. But Intellij is showing an error:
Could not autowire. No beans of 'WebTestClient' type found. more...
(Strg+F1)
New info: The test runs fine in Intellij, but not when running with maven.
Here is a test project with the problem:
https://github.com/kicktipp/demo
How can I use WebTestClient on my Helper class?
For what it's worth - I was able to fix this by simply specifying the AutoConfigureWebTestClient annotation explicitly:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureWebTestClient
public class MyTestClass {
}
You have to build webTestClient before use it in tests
Use below, it will work
#Autowired
ApplicationContext context;
#Autowired
WebTestClient webTestClient;
#Before
public void setup() throws Exception {
this.webTestClient = WebTestClient.bindToApplicationContext(this.context).build();
}
I confused with configuration for unit test:
This's my test class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class MyTest {
private MockMvc mockMvc;
#Autowired
private MyController myController;
#Before
public void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
public void test() {
}
#Configuration
static class Config {
#Bean
MyController myController() {
return new MyController();
}
}
}
When I run it, I get:
java.lang.IllegalStateException: springSecurityFilterChain cannot be
null. Ensure a Bean with the name springSecurityFilterChain
implementing Filter is present or inject the Filter to be used.
How to configure it properly?
I have a unit test setup using Mockito and Spring 4. My test looks like this:
#ContextConfiguration(classes = {
MyTestConfig.class,
SecurityConfig.class,
OAuth2Config.class
})
#RunWith(MockitoJUnitRunner.class)
public class ControllerAccessTests {
private MockMvc mockMvc;
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Mock
private CreditCardPaymentService creditCardPaymentService;
#InjectMocks
private CreditCardRestController creditCardRestController;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders
.standaloneSetup(creditCardRestController)
.apply(springSecurity(springSecurityFilterChain))
.build();
when(creditCardPaymentService.doPreAuthPayment(any())).thenReturn(null);
}
#Test
//.... some unit tests
With a configuration file that looks like this:
#Configuration
public class MyTestConfig {
#Bean
public FilterChainProxy springSecurityFilterChain(){
AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**");
DefaultSecurityFilterChain chain = new DefaultSecurityFilterChain(matcher);
return new FilterChainProxy(chain);
}
}
When I start the unit test springSecurityFilterChain is null, so it seems the configuration file MyTestConfig does not seem to get loaded. Any ideas?
Cheers
Tom
If you want to use mockito annotations and spring injection then:
1) Use #RunWith(SpringJUnit4ClassRunner.class)
2) Create an init method:
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
I'm using an autowired constructor in a service that when instantiated in the test class causes the #Value annotations to return null. Autowiring the dependencies directly solves the problem but the project follows the convention of using constructor based autowiring. My understanding is that instantiating the service in the test class is not creating it from the Spring IoC container which causes #Value to return null. Is there a way to create the service from the IoC container using constructor based autowiring without having to directly access the application context?
Example Service:
#Component
public class UpdateService {
#Value("${update.success.table}")
private String successTable;
#Value("${update.failed.table}")
private String failedTable;
private UserService userService
#Autowired
public UpdateService(UserService userService) {
this.userService = userService;
}
}
Example Test Service:
#RunWith(SpringJUnite4ClassRunner.class)
#SpringApplicationConfiguration(classes = {TestApplication.class})
#WebAppConfiguration
public class UpdateServiceTest {
private UpdateService updateService;
#Mock
private UserService mockUserService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
updateService = new UpdateService(mockUserService);
}
}
To make #Value work updateService should be inside of spring context.
The best practice for spring framework integration tests is to include application context in test context and autowiring test source in test:
...
public class UpdateServiceTest {
#Autowired
private UpdateService updateService;
...
Mock userService
Option with changing userService to protected and considering that test and source classes are in same package.
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
updateService.userService = mockUserService;
}
Option with reflection with Whitebox:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Whitebox.setInternalState(updateService, 'userService', mockUserService);
}
The #Value is filled by a property placeholder configurer which is a post processor in the spring context. As your UpdateService is not part of the context it is not processed.
Your setup looks a little like a unclear mixture of unit and integration test. For a unit tests you will not need a spring context at all . Simply make the #Value annotated members package protected and set them or use ReflectionTestUtils.setField() (both shown):
public class UpdateServiceTest {
#InjectMocks
private UpdateService updateService;
#Mock
private UserService mockUserService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(updateService, "successTable", "my_success");
updateService.failedTable = "my_failures";
}
}
For an integration test all wiring should be done by spring.
For this I added a inner config class providing the mock user service (the #Primary is only for the case you have any other user service in your context) and the mock is stored in a static member here to have simple access to the mock from the tests afterwards.
#RunWith(SpringJUnite4ClassRunner.class)
#SpringApplicationConfiguration(classes = {TestApplication.class, UpdateServiceTest.TestAddOn.class})
#WebAppConfiguration
public class UpdateServiceTest {
#Autowired
private UpdateService updateService;
private static UserService mockUserService;
static class TestAddOn {
#Bean
#Primary
UserService updateService() {
mockUserService = Mockito.mock(UserService.class);
return mockUserService;
}
}
}