I have a RestController that I'm attempting to test via Spring MVC Test. It has the following ModelAttribute in it:
#ModelAttribute("authUser")
public User authUser(#AuthenticationPrincipal SpringAuthUser springAuthUser) throws Exception {
User user = ConstantsHome.userprofileMgr.getUserByUserId(springAuthUser.getUsername(), true, true);
user.updateRights(null);
request.getSession().setAttribute(ConstantsHome.USEROBJECT_KEY, user);
return user;
}
When I run a test against this RestController, I'm getting a NullPointerException inside this authUser method.
Is there a way to mock this method such that the mocked method gets used instead of this one for testing? I've read other posts on this and thought I could just pass an "authUser" param in my test but that's not working. Ultimately trying to make this "authUser" not throw an NPE...here is my test...
#Test
public void testGetAllUsers() throws Exception {
String userJson = AvadaObjectMapper.getMapper().writeValueAsString(new User());
System.out.println("userJson=" + userJson);
MvcResult result = this.mockMvc.perform(get("/").param("authUser", userJson).accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andDo(print())
.andReturn();
String content = result.getResponse().getContentAsString();
assertTrue(content.contains("Hello"));
}
I was able to get my authUser to work via the test configuration class below. Pay attention to the .defaultRequest... line in particular as that is where the auth user gets established. I use the class below as the #ContextConfiguration class on all of my tests.
import com.avada.rest.api.users.UserService;
import com.avada.rest.api.users.TestUserService;
import com.avada.rest.security.SpringAuthUser;
import java.util.HashSet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
#Configuration
#ComponentScan(excludeFilters={
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=UserService.class)
})
public class TestSpringRestConfig {
public static final SpringAuthUser AUTH_USER =
new SpringAuthUser("test", "test",
new HashSet<GrantedAuthority>() {{
add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}}
);
#Bean
public UserService userService() {
return new TestUserService();
}
#Bean
public MockMvc mockMvc(WebApplicationContext wac) {
return MockMvcBuilders
.webAppContextSetup(wac)
.defaultRequest(MockMvcRequestBuilders.get("/").with(SecurityMockMvcRequestPostProcessors.user(AUTH_USER)))
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
}
Related
Need a help to write junit5 test case in springboot for a post api where it uses apache camel producer template to send message to kafka. Please find the controller class details for which junit test cases are required. Note-I don't have any service/repository layer for this.This is standalone controller which is responsible to publish message to kafka by using camel producer template.Thanks is advance.
Controller Class-->
`
`import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rms.inventory.savr.audit.model.AuditInfo;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MockKafkaProducerController {
#Autowired ProducerTemplate producerTemplate;
#Value("${audit.inbound.endpoint.kafka.uri:audit-json-topic}")
private String auditTopicKafka;
#Value("${camel.component.kafka.consumer.supply}")
private String supplyLineUpdateKafkaTopic;
#Value("${camel.component.kafka.consumer.demand}")
private String demandLineUpdateKafkaTopic;
#Value("${camel.component.kafka.consumer.supply-bucket}")
private String supplybucketTopicKafka;
#Value("${camel.component.kafka.consumer.demand-bucket}")
private String demandbucketTopicKafka;
#Value("${camel.component.kafka.consumer.availability}")
private String availabilityTopicKafka;
private Map<String, String> dataTypeTopicMap;
#PostConstruct
void init() {
dataTypeTopicMap =
Map.of(
"SUPPLY_LINE",
supplyLineUpdateKafkaTopic,
"SUPPLY_BUCKET",
supplybucketTopicKafka,
"DEMAND_LINE",
demandLineUpdateKafkaTopic,
"DEMAND_BUCKET",
demandbucketTopicKafka,
"AVAILABILITY",
availabilityTopicKafka);
}
#PostMapping("/api/mock/producer")
public ResponseEntity<Boolean> saveAuditInfo(#RequestBody AuditInfo auditInfo)
public ResponseEntity<Boolean> saveAuditInfo(
#RequestBody AuditInfo auditInfo, #RequestHeader("AUDIT_TYPE") String auditType)
throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
if (auditType == null || auditType.isEmpty()) {
auditType = "SUPPLY_LINE";
}
String topicName = dataTypeTopicMap.get(auditType);
// producerTemplate.
producerTemplate.sendBodyAndHeader(
auditTopicKafka, objectMapper.writeValueAsString(auditInfo), "messageFormat", "CANONICAL");
topicName, objectMapper.writeValueAsString(auditInfo), "messageFormat", "CANONICAL");
return ResponseEntity.ok(Boolean.TRUE);
}
#PostMapping("/api/inventory/audit/mock/producer")
public ResponseEntity<Boolean> publishInventoryAudit(#RequestBody String auditInfo)
public ResponseEntity<Boolean> publishInventoryAudit(
#RequestBody String auditInfo, #RequestHeader("AUDIT_TYPE") String auditType)
throws JsonProcessingException {
producerTemplate.sendBody(auditTopicKafka, auditInfo);
if (auditType == null || auditType.isEmpty()) {
auditType = "SUPPLY_LINE";
}
String topicName = dataTypeTopicMap.get(auditType);
producerTemplate.sendBody(topicName, auditInfo);
return ResponseEntity.ok(Boolean.TRUE);
}
}`
`
I tried to mock producer template but not able to fix.
So Im writing unit test a class that does bankId authentication and the unit test looks like this.
package se.kt.client;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpEntity;
import se.kt.common.vo.PublicApplicationForm;
import se.kt.models.BankIdAuthRequest;
import se.kt.models.BankIdAuthResponse;
import se.kt.models.BankIdCollectResponse;
import static org.mockito.ArgumentMatchers.any;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class BankIdClientTest {
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
#InjectMocks
private BankIdClient bankIdClient;
#BeforeEach
public void setUp() {
}
#Test
public void testBankIdAuthentication_success() throws InterruptedException {
PublicApplicationForm form = new PublicApplicationForm();
form.setSsn("123456-7890");
form.setIp_address("123.123.123.123");
BankIdAuthRequest authRequest = bankIdClient.authRequestFromApplicationForm(form, "123");
BankIdAuthResponse authResponse = new BankIdAuthResponse();
authResponse.setOrderRef("123456");
BankIdCollectResponse collectResponse = new BankIdCollectResponse();
collectResponse.setStatus("completed");
Mockito.when(restTemplate.postForEntity(anyString(), any(HttpEntity.class), any()))
.thenReturn(ResponseEntity.ok(authResponse));
Mockito.when(restTemplate.getForEntity(anyString(), any()))
.thenReturn(ResponseEntity.ok(collectResponse));
assertTrue(bankIdClient.bankIdAuthentication(authRequest));
}
}
And the class Im testing looks like this:
package se.kt.client;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import se.kt.common.domain.AbstractApplicationForm;
import se.kt.common.vo.PublicApplicationForm;
import se.kt.models.BankIdAuthRequest;
import se.kt.models.BankIdAuthResponse;
import se.kt.models.BankIdCollectResponse;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.AssertTrue;
import java.util.Objects;
#Component
public class BankIdClient {
private static final Logger log = LoggerFactory.getLogger(BankIdClient.class);
private final RestTemplate customRestTemplate;
private static final String CONTENT_TYPE = "Content-Type";
#Value("${BankId.AuthUrl}")
private String bankIdAuthUrl;
#Value("${BankId.CollectUrl}")
private String bankIdCollectUrl;
#Value("${BankId.SecretKey}")
private String bankIdSecretKey;
public BankIdClient(RestTemplate customRestTemplate) {
this.customRestTemplate = customRestTemplate;
}
public BankIdAuthRequest authRequestFromApplicationForm(PublicApplicationForm form, String jobId) {
BankIdAuthRequest bankIdAuthRequest = new BankIdAuthRequest();
bankIdAuthRequest.setPno(form.getSsn());
bankIdAuthRequest.setIpAddress(form.getIp_address());
bankIdAuthRequest.setRefID(jobId);
bankIdAuthRequest.setSecretKey(bankIdSecretKey);
bankIdAuthRequest.setAvsikt("Kt application");
return bankIdAuthRequest;
}
public boolean bankIdAuthentication(BankIdAuthRequest bankIdAuthRequest) throws InterruptedException {
//Setup header and body for request.
HttpHeaders headers = new HttpHeaders();
headers.add(CONTENT_TYPE, MediaType.APPLICATION_JSON.toString());
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
try {
String bankIdAuthFormJson = ow.writeValueAsString(bankIdAuthRequest);
HttpEntity<String> httpEntity = new HttpEntity<>(bankIdAuthFormJson, headers);
ResponseEntity<BankIdAuthResponse> authResponse = customRestTemplate.postForEntity(bankIdAuthUrl, httpEntity, BankIdAuthResponse.class);
bankIdCollectUrl += Objects.requireNonNull(authResponse.getBody()).getOrderRef();
ResponseEntity<BankIdCollectResponse> collectResponse;
do {
collectResponse = customRestTemplate.getForEntity(bankIdCollectUrl, BankIdCollectResponse.class);
Thread.sleep(1500);
if (Objects.requireNonNull(collectResponse.getBody()).getStatus().equals("completed"))
return true;
if (Objects.requireNonNull(collectResponse.getBody()).getStatus().equals("failed"))
return false;
} while (Objects.requireNonNull(collectResponse.getBody()).getStatus().equals("progress"));
} catch (JsonProcessingException e) {
log.info(e.getMessage());
} catch (NullPointerException e) {
log.info(e.toString());
log.info("BankId API not responding correctly. Check server connection");
}
return false;
}
public void cancelBankIdAuthentication(#Value("${BankId.CancelUrl}") String bankIdCancelUrl) {
customRestTemplate.postForEntity(bankIdCancelUrl, null, String.class);
}
}
Now for some reson this line:
ResponseEntity<BankIdAuthResponse> authResponse = customRestTemplate.postForEntity(bankIdAuthUrl, httpEntity, BankIdAuthResponse.class);
keeps producing the result authResponse = null indicating that
Mockito.when(restTemplate.postForEntity(anyString(), any(HttpEntity.class), any()))
.thenReturn(ResponseEntity.ok(authResponse));
is not working. Now I have been playing around with this for over 3h and i still get the same result. What could i be doing wrong?
#InjectMocks only works with #Mock-annotated fields, not with fields which get assigned a manually created mock. Therefore you need to change:
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
#InjectMocks
private BankIdClient bankIdClient;
to
#Mock
private RestTemplate restTemplate;
#InjectMocks
private BankIdClient bankIdClient;
I also recommend reading Why is my class not calling my mocked methods in unit test? which provides additional insights and points out some common mistakes when using Mockito or mocks in general.
I'm trying to get a PACT test running on JUnit5. We use JUnit4 for others, but this one will be JUnit5. The error occurs when running the JUnit5 test using the pact annotation on the RequestResponsePact method.
Error : No method annotated with #Pact was found on test class ConsumerContractTest for provider ''.
I've seen Basic Pact/Junit5 Test Setup fails. No method annotated with #Pact was found for provider error, but this is issue was due to the #PactTestFor(pactMethod = "examplePact") not matching the #Pact method name. But on my code it does match.
I can't seem to figure out why I get the error and especially why the error has an empty provider(provider '') despite defining one("some-provider").
Example code :
import au.com.dius.pact.consumer.MockServer
import au.com.dius.pact.consumer.Pact
import au.com.dius.pact.consumer.dsl.PactDslJsonArray
import au.com.dius.pact.consumer.dsl.PactDslWithProvider
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt
import au.com.dius.pact.consumer.junit5.PactTestFor
import au.com.dius.pact.model.RequestResponsePact
import groovyx.net.http.RESTClient
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.http.HttpStatus
#ExtendWith(PactConsumerTestExt.class)
class ConsumerContractTest {
#Pact(consumer = "some-consumer", provider = "some-provider")
RequestResponsePact examplePact(PactDslWithProvider builder) {
builder
.given("provider state")
.uponReceiving("Contract description")
.method("GET")
.matchPath("/endpoint")
.willRespondWith()
.status(200)
.headers(["Content-Type": "application/vnd.pnf.v1+json"])
.body(new PactDslJsonArray())
.toPact()
}
#Test
#PactTestFor(pactMethod = "examplePact")
void exampleTest(MockServer mockServer) {
def client = new RESTClient(mockServer.getUrl())
}
}
Not sure if that's just the gist you've posted here but I see the return word missing and also the #PactTestFor annotation missing the provider and version. Here is an example I have that works for my project.
import au.com.dius.pact.consumer.dsl.DslPart;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt;
import au.com.dius.pact.consumer.junit5.PactTestFor;
import au.com.dius.pact.core.model.PactSpecVersion;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import java.util.HashMap;
import java.util.Map;
import static com.example.mbbackend.config.Constants.*;
import static com.example.mbbackend.util.Utils.getRequestSpecification;
import static org.junit.jupiter.api.Assertions.assertEquals;
#ExtendWith(PactConsumerTestExt.class)
class GetActorIT {
Map<String, String> headers = new HashMap<>();
String path = "/api/mb/actor/";
#Pact(provider = PACT_PROVIDER, consumer = PACT_CONSUMER)
public RequestResponsePact createPact(PactDslWithProvider builder) {
headers.put("Content-Type", "application/json");
DslPart bodyReturned = new PactDslJsonBody()
.uuid("id", "1bfff94a-b70e-4b39-bd2a-be1c0f898589")
.stringType("name", "A name")
.stringType("family", "A family")
.stringType("imageUrl", "http://anyimage.com")
.close();
return builder
.given("A request to retrieve an actor")
.uponReceiving("A request to retrieve an actor")
.pathFromProviderState(path + "${actorId}", path + "1bfff94a-b70e-4b39-bd2a-be1c0f898589")
.method("GET")
.headers(headers)
.willRespondWith()
.status(200)
.body(bodyReturned)
.toPact();
}
#Test
#PactTestFor(providerName = PACT_PROVIDER, port = PACT_PORT, pactVersion = PactSpecVersion.V3)
void runTest() {
//Mock url
RequestSpecification rq = getRequestSpecification().baseUri(MOCK_PACT_URL).headers(headers);
Response response = rq.get(path + "1bfff94a-b70e-4b39-bd2a-be1c0f898589");
assertEquals(200, response.getStatusCode());
}
}
I have no idea why I am getting this error here. Any thoughts?
Here is my repository code
package movieweb.movies.repository;
import movieweb.movies.models.Movies;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface MoviesRepository extends CrudRepository<Movies, Integer> {
}
Here is my Controller code.
package movieweb.movies.controllers;
import movieweb.movies.models.Movies;
import movieweb.movies.models.UserMovies;
import movieweb.movies.repository.MoviesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ResponseStatusException;
#RestController
public class MoviesController {
#Autowired
private MoviesRepository moviesRepository;
#Autowired
private RestTemplate restTemplate;
#CrossOrigin
#GetMapping(path = "/movies")
public List<Movies> movies(){
List<Movies> allMovies = (List<Movies>) moviesRepository.findAll();
if (!allMovies.isEmpty()){
return allMovies;
} else {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Movies not found"
);
}
}
// #CrossOrigin
// #RequestMapping(path = "movies/user/{id}")
// public List<Movies> movie(#PathVariable("id") int id){
// return this.movies().stream().map(movie -> {
// Users[] user = restTemplate.getForObject("http://127.0.0.1:8082/users/" + id, Users[].class);
// return new Movies(movie.getMovieId(), movie.getMovieName(), "Description");
// })
// .collect(Collectors.toList());
// }
#CrossOrigin
#GetMapping(path="/movie/{id}")
public Movies getMovie(#PathVariable Integer id){
return moviesRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND, "Movie not found"
) );
}
#CrossOrigin
#DeleteMapping("/movie/delete/{id}")
void deleteMovie(#PathVariable Integer id) {
moviesRepository.deleteById(id);
}
#CrossOrigin
#PutMapping("/movie/update/{id}")
Movies updateMovie(#RequestBody Movies updateMovie, #PathVariable Integer id) {
return moviesRepository.findById(id)
.map(Movies -> {
Movies.setMovieName(updateMovie.getMovieName());
Movies.setMovieDescription(updateMovie.getMovieDescription());
return moviesRepository.save(Movies);
})
.orElseGet(() -> {
updateMovie.setMovieId(id);
return moviesRepository.save(updateMovie);
});
}
#CrossOrigin
#PostMapping(path="/newMovie")
public Movies addNewMovie (#RequestBody Movies data) {
return moviesRepository.save(data);
}
}
and here is my test (updated)
package movieweb.movies;
import movieweb.movies.controllers.MoviesController;
import movieweb.movies.models.Movies;
import movieweb.movies.repository.MoviesRepository;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.testng.annotations.BeforeMethod;
import java.util.ArrayList;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#SpringBootTest
#AutoConfigureMockMvc
class MovieApplicationTests {
#Autowired
MockMvc mockMvc;
#MockBean
MoviesRepository moviesRepository;
#MockBean
MoviesController moviesController;
#Autowired
private WebApplicationContext webApplicationContext;
#BeforeMethod
public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
void getAllMovies() throws Exception{
ArrayList<Movies> moviesList = new ArrayList<Movies>();
moviesList.add(new Movies(1, "Star Wars", "A New Hope"));
moviesList.add(new Movies(2, "Star Wars", "Empire Strikes Back"));
when(moviesRepository.findAll()).thenReturn(moviesList);
mockMvc.perform(get("/movies"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].movieName", is("Star Wars")))
.andExpect(jsonPath("$[0].movieDescription", is("A New Hope")))
.andExpect(jsonPath("$[1].movieName", is("Star Wars")))
.andExpect(jsonPath("$[1].movieDescription", is("Empire Strikes Back")));
Mockito.verify(moviesRepository, times(1)).findAll();
}
}
The error I am getting in my stacktrace is the following....
java.lang.AssertionError: JSON path "$"
Expected: a collection with size <2>
but: collection size was <0>
Why is it zero and not the 2 items I created in my movieList ArrayList?
I'm guessing its something to do with my configuration?
You are mocking your controller:
#MockBean
MoviesController moviesController;
Thus, you replaced the real controller under test with this mock.
To have real controller you need to get rid of these lines.
To further improve, learn about #WebMvcTest to test only the web slice of your app.
I have a test class that is running in Spring Boot 2.1.1 and Java 11 and no matter what I do, it runs on port 8080:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#RunWith( SpringJUnit4ClassRunner.class )
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = TestClass.Config.class
)
#ContextConfiguration(
classes = TestClass.Config.class
)
#TestPropertySource( properties = "server.port=0" )
public class TestClass
{
#LocalServerPort
private String port;
#Test
public void testPort() throws Exception
{
mockMvc
.perform(
MockMvcRequestBuilders.get( "/" )
)
.andExpect( MockMvcResultMatchers.status().isOk() );
}
#Configuration
#RestController
public static class Config
{
#Bean
ServletWebServerFactory servletWebServerFactory()
{
return new TomcatServletWebServerFactory();
}
#GetMapping( "/" )
public String test(HttpServletRequest request, HttpServletResponse response)
{
//This still shows no random port
System.out.println( request.getLocalPort() );
return "ok";
}
}
}
Even when I try this:
#Bean
ServletWebServerFactory servletWebServerFactory()
{
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort( SocketUtils.findAvailableTcpPort() );
return factory;
}
which does result in the field port as having a random port number, MockMvc still uses the default port for my controller.
How can I get it to use a random port?
Try setting the port to 0 , it worked for me.
#Bean
ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory(0);
}
Running the test twice produces 2 different random ports.
63957
64043
Try this. You are free to use TestRestTemplate instead of RestAssured and MockBean as required
import static org.hamcrest.Matchers.equalTo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import io.restassured.RestAssured;
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class BookIT_SpringBootTest_WithWebServerAndRestAssured {
#LocalServerPort
private int port;
#Test
public void myTest() {
RestAssured
.given()
.baseUri("http://localhost/api")
.port(port)
.queryParam("id", "1")
.when()
.get("/book/get-book-id")
.then()
.statusCode(200);
}
}