I have a test class that looks like this
I found out that the test when i use #WebMvcTest Does not recognize the url for some reason.Any help would suffice please .
After debugging i get that DefaultRequestBuilder =Null, DefaultRequestMatcher size=0
#AutoConfigureMockMvc()
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest({ShoppingCartController.class, HomeController.class})
#ContextConfiguration(classes = {SecurityConfig.class})
public class ShoppingCartControllerTest {
#Autowired
WebApplicationContext context;
#Autowired
private MockMvc mockMvc;
#MockBean
private BookService bookService;
#MockBean
private UserService userService;
#MockBean
private CartItemService cartItemService;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
public void showLoginPage() throws Exception {
mockMvc.perform(get("/login")
.accept(MediaType.TEXT_HTML)
.contentType(MediaType.TEXT_HTML)
)
.andExpect(model().attributeExists("classActiveLogin"))
.andReturn();
}
#Test
#WithMockUser(username = "V", authorities = {"USER"})
public void addItemToShoppingCart() throws Exception {
CartItem cartItem = new CartItem();
String qty = "2";
Book book = new Book();
User user = new User();
book.setId(1L);
book.getId();
cartItem.setBook(book);
when(userService.findByUsername(anyString())).thenReturn(user);
when(bookService.findOne(anyLong())).thenReturn(book);
when(cartItemService.addBookToCartItem(book, user, Integer.parseInt(qty))).thenReturn(cartItem);
ObjectMapper mapper = new ObjectMapper();
String bookAsString = mapper.writeValueAsString(book);
mockMvc
.perform(get("/shoppingCart/addItem")
.accept(MediaType.TEXT_HTML)
.contentType(MediaType.TEXT_HTML)
.param("book", bookAsString)
.param("qty", qty))
.andReturn();
}
#Configuration
#Import({PropertyTestConfiguration.class, SecurityUtility.class})
static class ContextConfiguration {
}
}
Only the test addItemToShoppingcCart passes , the other three have the same error as shown below , It is definitely not importing everything I need but I cant figure out what exactly it is.
java.lang.AssertionError: No ModelAndView found
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:35)
at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:65)
I don't understand why I t cant find models and views but when I use #
SpringBootTest and EasyMock everything passes ? what can I do ?
These are my controllers
#RequestMapping("/login")
public String login(Model model) {
model.addAttribute("classActiveLogin", true);
return "Myaccount";
}
#PreAuthorize("hasAuthority('USER')")
#RequestMapping("/addItem")
public String addItem(
#ModelAttribute("book") Book book,
#ModelAttribute("qty") String qty,
Model model, Principal principal
) {
User user = userService.findByUsername(principal.getName());
try {
book = bookService.findOne(book.getId());
if (Integer.parseInt(qty) > book.getInStockNumber()) {
model.addAttribute("notEnoughStock", true);
return "forward:/bookDetail?id=" + book.getId();
}
CartItem cartItem = cartItemService.addBookToCartItem(book, user, Integer.parseInt(qty));
model.addAttribute("addBookSuccess", true);
} catch (NullPointerException e) {
}
return "forward:/bookDetail?id=" + book.getId();
}
I have two controllers i am testing
#Controller
public class HomeController {
#Autowired
private JavaMailSender mailSender;
#Autowired
private MailConstructor mailConstructor;
#Autowired
private UserService userService;
#RequestMapping("/login")
public String login(Model model) {
model.addAttribute("classActiveLogin", true);
return "Myaccount";
}
And Second one which has Class level Mapping
#Controller
#RequestMapping("/shoppingCart")
public class ShoppingCartController {
#Autowired
private UserService userService;
// autowired services here
#PreAuthorize("hasAuthority('USER')")
#RequestMapping("/addItem")
public String addItem(
#ModelAttribute("book") Book book,
#ModelAttribute("qty") String qty,
Model model, Principal principal
) {
User user = userService.findByUsername(principal.getName());
try {
book = bookService.findOne(book.getId());
if (Integer.parseInt(qty) > book.getInStockNumber()) {
model.addAttribute("notEnoughStock", true);
return "forward:/bookDetail?id=" + book.getId();
}
CartItem cartItem = cartItemService.addBookToCartItem(book, user, Integer.parseInt(qty));
model.addAttribute("addBookSuccess", true);
} catch (NullPointerException e) {
}
return "forward:/bookDetail?id=" + book.getId();
}
Related
I am developing a rest api with spring boot and spring security.
the code looks like so:
#RestController
#RequestMapping(path = "/api")
#PreAuthorize("isAuthenticated()")
public class RestController {
#GetMapping(path = "/get", produces = "application/json")
public ResponseEntity<InDto> get(
#AuthenticationPrincipal final CustomUser user) {
// ...
return ResponseEntity.ok(outDto);
}
}
public class CustomUser {
// does not inherit from UserDetails
}
public class CustomAuthenticationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(
#NonNull final HttpServletRequest request,
#NonNull final HttpServletResponse response,
#NonNull final FilterChain filterChain)
throws ServletException, IOException {
if (/* condition */) {
// ...
final CustomUser user = new CustomUser(/* parameters */);
final Authentication authentication =
new PreAuthenticatedAuthenticationToken(user, "", new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
I would like to unit test the RestController class ideally without the security feature but I don't know how to inject a specific CustomUser object during test.
I have tried to manually add a user to the security context before each test (see below) but the user injected into the controller during test is not the mocked on.
#WebMvcTest(RestController.class)
#AutoConfigureMockMvc(addFilters = false)
class RestControllerTest {
#Autowired private MockMvc mockMvc;
private CustomerUser userMock;
#BeforeEach
public void skipSecurityFilter() {
userMock = Mockito.mock(CustomUser.class);
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
final Authentication auth = new PreAuthenticatedAuthenticationToken(userMock, null, List.of());
SecurityContextHolder.getContext().setAuthentication(auth);
}
#Test
void test() {
mockMvc.perform(
MockMvcRequestBuilders.get("/api/get")
.contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk());
}
}
What is wrong? How to inject the specific userMock into the controller to perform the test?
EDIT to test with #WithMockCustomUser
as suggested in the doc https://docs.spring.io/spring-security/reference/servlet/test/method.html#test-method-withsecuritycontext i have updated the test to:
#Retention(RetentionPolicy.RUNTIME)
#WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public #interface WithMockCustomUser {
}
#Service
public class WithMockCustomUserSecurityContextFactory
implements WithSecurityContextFactory<WithMockCustomUser> {
#Override
public SecurityContext createSecurityContext(final WithMockCustomUser customUser) {
final SecurityContext context = SecurityContextHolder.createEmptyContext();
final Authentication auth =
new PreAuthenticatedAuthenticationToken(Mockito.mock(IUser.class), null, List.of());
context.setAuthentication(auth);
return context;
}
}
#WebMvcTest(RestController.class)
#AutoConfigureMockMvc(addFilters = false)
class RestControllerTest {
#Autowired private MockMvc mockMvc;
private CustomerUser userMock;
#BeforeEach
public void skipSecurityFilter() {
userMock = Mockito.mock(CustomUser.class);
}
#Test
#WithMockCustomUser
void test() {
mockMvc.perform(
MockMvcRequestBuilders.get("/api/get")
.contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk());
}
}
but the user object in the controller is still not the mock (created in the factory)
I rewrote the test to initialise the security context within the test
#WebMvcTest(RestController.class)
#AutoConfigureMockMvc
#Import(value = {
CustomAuthenticationFilter.class
})
class RestControllerTest {
#Autowired private MockMvc mockMvc;
private CustomerUser userMock;
#BeforeEach
public void skipSecurityFilter() {
userMock = Mockito.mock(CustomUser.class);
}
#Test
void test() {
PreAuthenticatedAuthenticationToken(userMock, null, List.of());
SecurityContextHolder.getContext().setAuthentication(auth);
mockMvc.perform(MockMvcRequestBuilders.get("/api/get").contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk());
}
}
and it works.
Not sure exactly why the it does not work with the #BeforeEach.
Currently struggling with problem when I get 'mapping error for request' with following controller/test configuration.
Controller:
#Slf4j
#Validated
#RestController
#RequiredArgsConstructor
public class AdtechController {
private final AdtechService adtechService;
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
log.trace("execute submitSession with {}", requestDto);
ResponseDtoresponse = adtechService.submitSession(requestDto);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#ExceptionHandler(AdtechServiceException.class)
public ResponseEntity<AdtechErrorResponse> handleAdtechServiceException(AdtechServiceException e) {
return new ResponseEntity<>(new AdtechErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#SpringJUnitConfig({AdtechTestConfig.class})
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#Test
public void testSubmitSession() throws Exception {
RequestDto requestDto = new RequestDto ();
requestDto.setKyivstarId("1123134");
requestDto.setMsisdn("123476345242");
requestDto.setPartnerId("112432523");
requestDto.setPartnerName("125798756");
String request = OBJECT_MAPPER.writeValueAsString(requestDto);
System.out.println("REQUEST: " + request);
String response = OBJECT_MAPPER.writeValueAsString(new ResponseDto("123"));
System.out.println("RESPONSE: " + response);
mockMvc.perform(post("/subscriber/session")
.content(MediaType.APPLICATION_JSON_VALUE)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(response)));
}
}
Configuration:
#Configuration
public class AdtechTestConfig {
#Bean
public AdtechService adtechTestService() {
return requestDto -> new AdtechResponseDto("123");
}
}
After test execution I get No mapping for POST /subscriber/session
The reason for the struggle is that my code from other modules with the same configuration works fine. Can somebody point out what am I missing ? Thanks in advance!
Apparently you are loading a configuration class to mock beans, this interferes with the other parts of Spring Boot and probably leads to partially loading your application. I suspect only the mocked service is available.
Instead of the test configuration use #MockBean to create a mock for the service and register behaviour on it.
#SpringBootTest
#AutoConfigureMockMvc
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#MockBean
private AdtechService mockService;
#BeforeEach
public void setUp() {
when(mockService.yourMethod(any()).thenReturn(new AdtechResponseDto("123"));
}
#Test
public void testSubmitSession() throws Exception {
// Your original test method
}
}
If the only thing you want to test is your controller you might also want to consider using #WebMvcTest instead of #SpringBootTest.
#WebMvcTest(AdTechController.class)
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#MockBean
private AdtechService mockService;
#BeforeEach
public void setUp() {
when(mockService.yourMethod(any()).thenReturn(new AdtechResponseDto("123"));
}
#Test
public void testSubmitSession() throws Exception {
// Your original test method
}
}
This will load a scaled-down version of the context (only the web parts) and will be quicker to run.
try this:
#Slf4j
#Validated
#RestController
#RequiredArgsConstructor
public class AdtechController {
private AdtechService adtechService;
public AdtechController (AdtechService adtechService) {
this.adtechService= adtechService;
}
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
log.trace("execute submitSession with {}", requestDto);
ResponseDtoresponse = adtechService.submitSession(requestDto);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#ExceptionHandler(AdtechServiceException.class)
public ResponseEntity<AdtechErrorResponse> handleAdtechServiceException(AdtechServiceException e) {
return new ResponseEntity<>(new AdtechErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#SpringJUnitConfig({AdtechTestConfig.class})
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#Autowired
private AdtechService adtechService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mvc = MockMvcBuilders.standaloneSetup(new AdtechController(adtechService)).build();
}
#Test
public void testSubmitSession() throws Exception {
RequestDto requestDto = new RequestDto ();
requestDto.setKyivstarId("1123134");
requestDto.setMsisdn("123476345242");
requestDto.setPartnerId("112432523");
requestDto.setPartnerName("125798756");
String request = OBJECT_MAPPER.writeValueAsString(requestDto);
System.out.println("REQUEST: " + request);
String response = OBJECT_MAPPER.writeValueAsString(new ResponseDto("123"));
System.out.println("RESPONSE: " + response);
mockMvc.perform(post("/subscriber/session")
.content(MediaType.APPLICATION_JSON_VALUE)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(response)));
}
}
Is the AdtechTestConfig.class introducing the /ad-tech path segment in to your test request? If so, this is why your test is trying the path /ad-tech/subscriber/session instead of /subscriber/session.
If this is actually the correct uri, then you may add #RequestMapping to the controller like below or just to the post method itself
#Slf4j
#Validated
#RestController
#RequestMapping("/ad-tech")
#RequiredArgsConstructor
public class AdtechController {
private final AdtechService adtechService;
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
...
So I am working with a working UI, and using a DB2 database. I am trying to run unit testing on the controller/service/dao layers and I am using mockito and junit to test. Here are the pieces of each layer:
Measures.java
#Controller
#RequestMapping(value = "/measures"})
public class Measures {
#Resource
private CheckUpService checkUpService;
public void setCheckUpService(CheckUpService checkUp) {
this.checkUpService = checkUpService;
}
#RequestMapping(value = "/eligibility/{userId}/{effDate}/{stageInd}", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody List<Model> findEligibility(#PathVariable int userId, #PathVariable String effDate, #PathVariable String stageInd) throws Exception
{
List<Model> result = new ArrayList<Model>();
if (stageInd.equals("stage"))
{
result = checkUpService.findEligibilityStage(userId, effDate);
}
if (stageInd.equals("prod"))
{
result = checkUpService.findEligibility(userId, effDate);
}
return result;
}
...
}
CheckUpService.java
public class CheckUpService {
#Resource
EligibilityDao eligDao;
public List<Model> findEligibility(int userId, String effDate) throws Exception
{
return eligDao.findEligibility(userId, effDate, db_table);
}
}
EligibilityDao.class
public class EligibilityDao {
public List<Model> findEligibility(int userId, String effDate, String table) throws Exception
{
// uses some long sql statement to get some information db2 database and
// jdbctemplate helps return that into a list.
}
}
Here is the controller test that I am trying to do, I've spent about 10 hours on this and I really can't figure out why it's giving me a 406 error instead of 200.
ControllerTest.java
#EnableWebMvc
#WebAppConfiguration
public class ControllerTest {
#Autowired
private Measures measures;
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private List<Model> findEligibility() {
List<Model> list = new ArrayList<>();
Model test_model = new Model();
test_model.setUserId(99);
test_model.setCreateID("testUser");
test_model.setEffDate("2020-07-30");
list.add(test_model);
return list;
}
#Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void test_find() throws Exception {
CheckUpService checkUpService = mock(CheckUpService.class);
when(checkUpService.findEligibility(99, "2020-07-30")).thenReturn(findEligibility());
measures.setCheckUpService(checkUpService);
String URI = "/measures/eligibility/99/2020-07-30/prod";
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(URI).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
MvcResult handle = mockMvc.perform(requestBuilder).andReturn();
// MvcResult handle = mockMvc.perform(requestBuilder).andExpect(status().isOk()).andReturn();
MvcResult result = mockMvc.perform(asyncDispatch(handle)).andExpect(status().isOk()).andReturn();
// assertThat(result.getResponse().getContentAsString()).isEqualTo(findEligibility());
}
}
The MvcResult result is what is throwing the "StatusExpected <200> but was <406>" error in junit and i'm going mad on why it is. Another issue is that, if you can see, I commented out the handle with the .andExpect(status().isOk()) and that one was also throwing the same issue. Is it something i'm setting up wrong with the test or something?
I could not reproduce your issue. However, I got this working.
So, no big changes to the Controller, but I removed the field injection in favor of constructor injection.
#Controller
#RequestMapping(value = "/measures")
public class Measures {
private final CheckUpService checkUpService;
public Measures(CheckUpService checkUpService) {
this.checkUpService = checkUpService;
}
#RequestMapping(value = "/eligibility/{userId}/{effDate}/{stageInd}", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody List<Model> findEligibility(#PathVariable int userId, #PathVariable String effDate, #PathVariable String stageInd) throws Exception {
List<Model> result = new ArrayList<>();
if (stageInd.equals("stage")) {
result = checkUpService.findEligibility(userId, effDate);
}
if (stageInd.equals("prod")) {
result = checkUpService.findEligibility(userId, effDate);
}
return result;
}
}
The same for the service class.
#Service
public class CheckUpService {
private final EligibilityDao dao;
public CheckUpService(EligibilityDao dao) {
this.dao = dao;
}
public List<Model> findEligibility(int userId, String effDate) throws Exception {
return dao.findEligibility(userId, effDate, "demo value");
}
}
and here's the test. Instead of initializing the MockMvc and injecting the web context, I inject MockMvc. Also, using #MockBean, you can inject mocks. So, I removed the mock creation from the test method to the initialization part.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MeasuresTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private CheckUpService service;
#Test
public void test_find() throws Exception {
Model model = new Model(99, "2020-08-02", "2020-07-30");
when(service.findEligibility(99, "2020-07-30"))
.thenReturn(Collections.singletonList(model));
String URI = "/measures/eligibility/99/2020-07-30/prod";
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(URI)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON);
final MvcResult mvcResult = mockMvc.perform(requestBuilder)
.andExpect(status().isOk()).andReturn();
final String json = mvcResult.getResponse().getContentAsString();
final List<Model> models = new ObjectMapper().readValue(json, new TypeReference<>() {
});
Assert.assertEquals(1, models.size());
Assert.assertEquals(model, models.get(0));
}
}
In the post, I could not find any reason why you used asyncDispatch, so I just did not use it.
I learning Spring Boot web application with .jsp, and I'm struggling a lot with the testing concepts. From the SO and YT guides I implemented the Mockito thing, but honestly I do not clearly undesrtand how does it work.
I have a Registration form with 4 fields for name, lastname, email and password. This POST request is handled by the registerAction method in RegisterController. In this method I have two self-written validators for email and password. The tests should handle the cases when User data are given properly and if the errors are sent when inputs are not correct.
I tried to write tests for the controller but I'm constantly getting an exception NullPointerExpection. Looking into the debugger, the User object sent from the testing class has null attributes, which probably is the reason the exceptions.
Testing class:
#SpringBootTest
#AutoConfigureMockMvc
class RegisterControllerTest {
#Autowired
private WebApplicationContext wac;
#MockBean
private UserService userService;
#Autowired
private Gson gson;
#Autowired
private MockMvc mockMvc;
#BeforeEach
void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.apply(springSecurity()).build();
}
#Test
void show_register_action() throws Exception {
User user = prepareUserEmpty();
this.mockMvc.perform(post("/adduser")
.contentType(MediaType.APPLICATION_JSON)
.content(gson.toJson(user)))
.andDo(print())
.andExpect(status().isOk());
}
private User prepareUserEmpty(){
User user = new User();
user.setEmail("");
user.setPassword("");
user.setName("");
user.setLastName("");
return user;
}
}
RegisterController:
#Controller public class RegisterController {
#Autowired
private UserService userService;
#Autowired
private EmailSender emailSender;
#Autowired
MessageSource messageSource; // Allows to obtain messages from message.properties to Java code
#POST
#RequestMapping(value = "/adduser")
public String registerAction(User user, BindingResult result, Model model, Locale locale){ // BindingResult for validation, Locale for messageSource
String returnPage = "register";
User userExist = userService.findUserByEmail(user.getEmail());
new UserRegisterValidator().validate(user, result);
new UserRegisterValidator().validateEmailExist(userExist, result);
if (!(result.hasErrors())){
userService.saveUser(user);
model.addAttribute("message", messageSource.getMessage("user.register.success.email", null, locale));
returnPage = "index";
}
return returnPage;
} }
Validators:
public class UserRegisterValidator implements Validator {
#Override
public boolean supports(Class <?> cls){
return User.class.equals(cls);
}
#Override
public void validate(Object obj, Errors errors){
User u = (User) obj;
ValidationUtils.rejectIfEmpty(errors, "name", "error.userName.empty");
ValidationUtils.rejectIfEmpty(errors, "lastName", "error.userLastName.empty");
ValidationUtils.rejectIfEmpty(errors, "email", "error.userEmail.empty");
ValidationUtils.rejectIfEmpty(errors, "password", "error.userPassword.empty");
if (!u.getEmail().equals(null)){
boolean isMatch = AppdemoUtils.checkEmailOrPassword(AppdemoConstants.EMAIL_PATTERN, u.getEmail());
if (!isMatch)
errors.rejectValue("email", "error.userEmailIsNotMatch");
}
if (!u.getPassword().equals(null)){
boolean isMatch = AppdemoUtils.checkEmailOrPassword(AppdemoConstants.PASSWORD_PATTERN, u.getPassword());
if (!isMatch)
errors.rejectValue("password", "error.userPasswordIsNotMatch");
}
}
public void validateEmailExist(User user, Errors errors){
if (user != null)
errors.rejectValue("email", "error.userEmailExist");
}
}
I am still getting Access Denied although my test method is annotated with #WithMockUser. Why this is not working in integration test? Everything is fine with test with #WebAppConfiguration and MockMvc.
Test Class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FileUploadIntegrationTest {
#Autowired
private TestRestTemplate restTemplate;
#MockBean
private FileStorageService storageService;
#Test
public void classPathResourceTest() throws Exception {
ClassPathResource resource = new ClassPathResource("/test/testFile.txt", getClass());
assertThat(resource.exists(), is(true));
}
#Test
#WithMockUser(username="tester",roles={"USER"})
public void shouldUploadFile() throws Exception {
ClassPathResource resource = new ClassPathResource("/test/testFile.txt", getClass());
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("file", resource);
ResponseEntity<String> response = this.restTemplate.postForEntity("/files", map, String.class);
// assertThat(response.getStatusCode(), is(HttpStatus.OK));
then(storageService).should().addFile((any(String.class)), any(MultipartFile.class));
}
}
Controller class:
#RestController
#RequestMapping("/files")
#PreAuthorize(value = "hasRole('ROLE_USER')")
public class FileUploadController {
private FileStorageService fileStorageService;
private AuthenticationFacade authenticationFacade;
#Autowired
public FileUploadController(FileStorageService fileUploadService, AuthenticationFacade authenticationFacade) {
this.fileStorageService = fileUploadService;
this.authenticationFacade = authenticationFacade;
}
#ResponseBody
#PostMapping
public ResponseEntity<UUID> uploadFile(#RequestParam("file") MultipartFile file) {
UUID uuid = this.fileStorageService.addFile(authenticationFacade.getAuthentication().getName(), file);
if (uuid != null) return ResponseEntity.ok(uuid);
else return (ResponseEntity<UUID>) ResponseEntity.badRequest();
}
}
Couldn't solve this with #WithMockUser.
You can try using the Profiles approach described here: https://stackoverflow.com/a/35192495/3010484.