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();
}
}
This is my integration test controller class. Method get all team and there was a problem with compilation:
#SpringJUnitWebConfig(classes = CrewApplication.class)
public class Team_Controller_Integration_Test {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup() throws Exception
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
MockitoAnnotations.initMocks(this);
}
#Test
void getAccount() throws Exception {
this.mockMvc.perform(get("/teams")
.accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$version").value(null))
.andExpect(jsonPath("$name").value("Apacze"))
.andExpect(jsonPath("$createOn").value(null))
.andExpect(jsonPath("modifiedOn").value(null))
.andExpect(jsonPath("$description").value("grupa programistow"))
.andExpect(jsonPath("$city").value("Włocławek"))
.andExpect(jsonPath("$headcount").value(null));
}
}
This is my error:
java.lang.NullPointerException
On the other hand I create test for Db adn I have problem becouse after add mock elements to db they return null:
#RunWith(SpringRunner.class)
#DataJpaTest
public class Team_database_integration_test {
#MockBean
private TeamRepository teamRepository;
#Autowired
private TestEntityManager testEntityManager;
#Test
public void testDb(){
Team team = new Team(1L,"teamName","teamDescription","krakow",7);
testEntityManager.persist(team);
testEntityManager.flush();
System.out.println(team);
}
}
Add this dependency declaration to test case
#Autowired
private WebApplicationContext webApplicationContext;
and correct the initialization
#Before
public void setup() throws Exception
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
MockitoAnnotations.initMocks(this);
}
try changing to this signature,i think content type is by default -json.Try without assertions first then add assertions for validations!
MvcResult CDTO = this.mockMvc.perform(get("/plan/1"))
.andExpect(status().isOk())
.andReturn();
With Spring Boot of version 1.4 sone test annotations where deprecated "in favor of {#link SpringBootTest}".
Hovewer simply replacing deprecated annotations with new one, causes one strange side affect for me, #PostConstruct is called twice.
So lets assume that it was before
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {ApplicationTestContext.class})
#IntegrationTest
#Transactional
public class EmployeesControllerSpringTest {
#Inject
private EmployeeRepository employeeRepository;
#Inject
private VenueRepository venueRepository;
#Inject
private TestUtilDummyObjects dummyObjects;
#Inject
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
#Inject
private EntityManager entityManager;
#Inject
private ExceptionTranslator exceptionTranslator;
private MockMvc mockMvc;
#PostConstruct
public void postConstruct() {
EmployeesController sut = new EmployeesController(employeeRepository);
mockMvc = MockMvcBuilders
.standaloneSetup(sut)
.setControllerAdvice(exceptionTranslator)
.setMessageConverters(jacksonMessageConverter)
.build();
}
So, replasing deprecated annottions with the following
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {ApplicationTestContext.class})
#Transactional
causes #PostConstruct to be called twice.
Maybe someone can suggest, what am I doing wrong?
Please see ApplicationTestContext.class below:
//#TestConfiguration
//#SpringBootConfiguration
#ComponentScan(excludeFilters = {#ComponentScan.Filter(type = FilterType.REGEX,
pattern = "somepath.*")})
#EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class})
#EnableConfigurationProperties({ApplicationProperties.class, LiquibaseProperties.class})
#EnableAspectJAutoProxy(proxyTargetClass = false)
public class ApplicationTestContext extends WebMvcConfigurerAdapter {
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new LocalDateConverter(Constants.DATE_FORMAT));
registry.addConverter(new LocalDateTimeConverter(Constants.DATE_TIME_FORMAT));
}
}
UPDATE
Following #bhantol sugestion (get rid of all redundand annotations), I've tried to run official sample https://spring.io/guides/gs/spring-boot/.
Simply downloading sources and changing #Before to #PostConstruct still causing it to be called twice.
code from the sample is below:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerIT {
#LocalServerPort
private int port;
private URL base;
#Autowired
private TestRestTemplate template;
//#Before
#PostConstruct
public void setUp() throws Exception {
this.base = new URL("http://localhost:" + port + "/");
System.out.println("");
}
#Test
public void getHello() throws Exception {
ResponseEntity<String> response = template.getForEntity(base.toString(),
String.class);
assertThat(response.getBody(), equalTo("Greetings from Spring Boot!"));
}
}
Not sure, but seems like a potential bug.
I'm triying to write a test from a controller.
The controller call a service who call an autowired repository.
Here is my class right now
#RunWith(MockitoJUnitRunner.class)
public class AdminDestinationControllerTest {
private final PTUser user = new PTUser();
private MockMvc mockMvc;
#InjectMocks
private AdminDestinationController adminDestinationController;
#Mock private RoutingDestinationServiceImpl routingDestinationService;
#Mock private PTRoutingDestinationRepository destinationRepository;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(adminDestinationController).build();
}
#Test
public void setCost_UnknownCode() throws Exception {
when(routingDestinationService.setCost(Mockito.anyString(), Mockito.any())).thenCallRealMethod();
when(destinationRepository.setCost(Mockito.anyString(), Mockito.any())).thenReturn(Optional.empty());
mockMvc.perform(post("/admin/destinations/cost").content("{\"code\":\"99999\", \"cost\":\"2\"}").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
}
}
But in the service, the repository is null.
Any ideas of how I could do ?
Thank you
I'm working to test (via JUnit4 and Spring MockMvc) a REST service adapter using Spring-boot. The adapter simply passes along requests made to it, to another REST service (using a custom RestTemplate) and appends additional data to the responses.
I'd like to run MockMvc tests to perform controller integration tests, but want to override the RestTemplate in the controller with a mock to allow me to predefine the 3rd party REST response and prevent it from being hit during each test. I've been able to accomplish this by instantiating a MockMvcBuilders.standAloneSetup() and passing it the controller to be tested with the mock injected as listed in this post (and my setup below), however I am not able to do the same using MockMvcBuilders.webAppContextSetup().
I've been through a few other posts, none of which answer the question as to how this might be accomplished. I would like to use the actual Spring application context for the tests instead of a standalone to prevent any gaps as the application is likely to grow.
EDIT: I am using Mockito as my mocking framework and am trying to inject one of its mocks into the context. If this isn't necessary, all the better.
Controller:
#RestController
#RequestMapping(Constants.REQUEST_MAPPING_PATH)
public class Controller{
#Autowired
private DataProvider dp;
#Autowired
private RestTemplate template;
#RequestMapping(value = Constants.REQUEST_MAPPING_RESOURCE, method = RequestMethod.GET)
public Response getResponse(
#RequestParam(required = true) String data,
#RequestParam(required = false, defaultValue = "80") String minScore
) throws Exception {
Response resp = new Response();
// Set the request params from the client request
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(Constants.PARAM_DATA, data);
parameters.put(Constants.PARAM_FORMAT, Constants.PARAMS_FORMAT.JSON);
resp = template.getForObject(Constants.RESTDATAPROVIDER_URL, Response.class, parameters);
if(resp.getError() == null){
resp.filterScoreLessThan(new BigDecimal(minScore));
new DataHandler(dp).populateData(resp.getData());
}
return resp;
}
}
Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#SpringApplicationConfiguration(classes = MainSpringBootAdapter.class)
#TestPropertySource("/application-junit.properties")
public class WacControllerTest {
private static String controllerURL = Constants.REQUEST_MAPPING_PATH + Constants.REQUEST_MAPPING_RESOURCE + compressedParams_all;
private static String compressedParams_all = "?data={data}&minScore={minScore}";
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#InjectMocks
private Controller Controller;
#Mock
private RestTemplate rt;
#Value("${file}")
private String file;
#Spy
private DataProvider dp;
#Before
public void setup() throws Exception {
dp = new DataProvider(file);
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void testGetResponse() throws Exception {
String[] strings = {"requestData", "100"};
Mockito.when(
rt.getForObject(Mockito.<String> any(), Mockito.<Class<Object>> any(), Mockito.<Map<String, ?>> any()))
.thenReturn(populateTestResponse());
mockMvc.perform(get(controllerURL, strings)
.accept(Constants.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultHandlers.print());
Mockito.verify(rt, Mockito.times(1)).getForObject(Mockito.<String> any(), Mockito.<Class<?>> any(), Mockito.<Map<String, ?>> any());
}
private Response populateTestResponse() {
Response resp = new Response();
resp.setScore(new BigDecimal(100));
resp.setData("Some Data");
return resp;
}
}
Spring's MockRestServiceServer is exactly what you're looking for.
Short description from javadoc of the class:
Main entry point for client-side REST testing. Used for tests that involve direct or indirect (through client code) use of the RestTemplate. Provides a way to set up fine-grained expectations on the requests that will be performed through the RestTemplate and a way to define the responses to send back removing the need for an actual running server.
Try to set up your test like this:
#WebAppConfiguration
#ContextConfiguration(classes = {YourSpringConfig.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class ExampleResourceTest {
private MockMvc mockMvc;
private MockRestServiceServer mockRestServiceServer;
#Autowired
private WebApplicationContext wac;
#Autowired
private RestOperations restOperations;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
mockRestServiceServer = MockRestServiceServer.createServer((RestTemplate) restOperations);
}
#Test
public void testMyApiCall() throws Exception {
// Following line verifies that our code behind /api/my/endpoint made a REST PUT
// with expected parameters to remote service successfully
expectRestCallSuccess();
this.mockMvc.perform(MockMvcRequestBuilders.get("/api/my/endpoint"))
.andExpect(status().isOk());
}
private void expectRestCallSuccess() {
mockRestServiceServer.expect(
requestTo("http://remote.rest.service/api/resource"))
.andExpect(method(PUT))
.andRespond(withSuccess("{\"message\": \"hello\"}", APPLICATION_JSON));
}
}
Here's another solution. Simply put, it just creates a new RestTemplate bean and overrides the one already registered.
So while it performs produces the same functionality as #mzc answer, it allows me to use Mockito to craft the response and verification matchers a bit easier.
Not that it's more than a couple lines of code, but it also prevents from having to add additional code to convert from the Response object to a string for the above mockRestServiceServer.expect().andRespond(<String>) method's arg.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#SpringApplicationConfiguration(classes = MainSpringBootAdapter.class)
#TestPropertySource("/application-junit.properties")
public class WacControllerTest {
private static String Controller_URL = Constants.REQUEST_MAPPING_PATH + Constants.REQUEST_MAPPING_RESOURCE + compressedParams_all;
#Configuration
static class Config {
#Bean
#Primary
public RestTemplate restTemplateMock() {
return Mockito.mock(RestTemplate.class);
}
}
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#InjectMocks
private Controller Controller;
#Mock
private RestTemplate rt;
#Value("${file}")
private String file;
#Spy
private DataProvider dp;
#Before
public void setup() throws Exception {
dp = new DataProvider(file);
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.rt = (RestTemplate) this.wac.getBean("restTemplateMock");
}
#Test
public void testGetResponse() throws Exception {
String[] strings = {"request", "100"};
//Set the request params from the client request
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(Constants.PARAM_SINGLELINE, strings[0]);
parameters.put(Constants.PARAM_FORMAT, Constants.PARAMS_FORMAT.JSON);
Mockito.when(
rt.getForObject(Mockito.<String> any(), Mockito.<Class<Object>> any(), Mockito.<Map<String, ?>> any()))
.thenReturn(populateTestResponse());
mockMvc.perform(get(Controller_URL, strings)
.accept(Constants.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultHandlers.print());
Mockito.verify(rt, Mockito.times(1)).getForObject(Mockito.<String> any(), Mockito.<Class<?>> any(), Mockito.<Map<String, ?>> any());
}
private Response populateTestResponse() {
Response resp = new Response();
resp.setScore(new BigDecimal(100));
resp.setData("Some Data");
return resp;
}
}
org.springframework.boot.test.mock.mockito.MockBean #MockBean helped me out.