How to test file upload in spring boot? - java

I have implemented a rest service similar to this one.
UserController.java
#RestController
#RequestMapping(path = "/user")
public class UserController {
private final UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
#PostMapping(path = "/{id}/avatar")
public void handleUpload(#PathVariable("id") int id, #RequestParam("file") MultipartFile file) {
if (file == null) {
throw new DashboardException("Please select a valid picture");
}
userService.setAvatar(id, file);
}
}
Now I am trying to test the rest endpoint with:
UserControllerEndpointTest.java
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
#WebAppConfiguration
public class UserControllerEndpointTest {
private static final int userId = 42;
private static final String urlPath = String.format("/user/%d/avatar", userId);
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
private UserController controller;
private UserService service;
#Before
public void setUp() throws NoSuchFieldException, IllegalAccessException {
mockMvc = webAppContextSetup(webApplicationContext).build();
service = Mockito.mock(UserService.class);
injectField(controller, "userService", service);
}
#Test
public void successfullySetAvatar() throws Exception {
final InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("test.png");
final MockMultipartFile avatar = new MockMultipartFile("test.png", "test.png", "image/png", inputStream);
doNothing().when(service).setAvatar(userId, avatar);
final MvcResult result = mockMvc.perform(fileUpload(urlPath).file(avatar))
.andExpect(status().isOk())
.andReturn();
verify(service).setAvatar(userId, avatar);
}
}
This fails with 400 - Required request part 'file' is not present.
What am I missing?

Probably you need to change
new MockMultipartFile("test.png", "test.png", "image/png", inputStream);
to
new MockMultipartFile("file", "test.png", "image/png", inputStream);
as the uploaded file parameter name is 'file'

Related

Test mocking return empty body

I am trying to make testings for my user controller but when I run the test it fails because the response body is empty.
Note that the response code is 200 so i dont see where this problem comes from...
#WebMvcTest(controllers = {UserRestController.class})
public class UserControllerTest {
#Autowired
private WebApplicationContext webApplicationContext;
#MockBean
private UserService service;
private MockMvc mockMvc;
private User user1;
private User user2;
#BeforeEach
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
this.user1 = User.builder()
.email("doe.jean#mymel.com")
.username("Djin")
.build();
this.user2 = User.builder()
.email("doe.john#mymel.com")
.username("Jodo")
.build();
}
#Test
public void test_shouldReturnAllUsers() throws Exception {
Mockito.when(service.getUsers(Pageable.unpaged())).thenReturn(new PageImpl<>(Arrays.asList(user1, user2)));
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(APIPaths.V1_USER_BASE + "/all")
.accept(MediaType.APPLICATION_JSON))
.andExpect(request().asyncStarted())
.andReturn();
mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().is(200))
.andExpect(jsonPath("$.size()", Matchers.is(2)))
.andDo(print());
}
}

How to write an integration test in JAVA

i'm learning yet testing in java and i'm trying to write an integration test for controller below:
public class OrderController {
#Autowired
private OrderService orderService;
public OrderController(OrderService service) {
this.orderService = service;
}
#PostMapping(value = "/add")
#ApiOperation(value = "Add", response = AddOrderResult.class)
public Response<AddOrderResult> add(#ModelAttribute AddUpdateOrderEnter enter) {
return new Response<>(orderService.addOrder(enter));
}
#PostMapping(value = "/addOrderParts")
#ApiOperation(value = "AddOrderParts", response = GeneralResult.class)
public Response<GeneralResult> AddOrderParts(#ModelAttribute #ApiParam("请求参数") AddOrderPartsEnter enter) {
return new Response<>(orderService.AddOrderParts(enter));
}
#GetMapping(value = "/list")
#ApiOperation(value = "Order List", response = OrderDetailsResult.class)
public Response<List<OrderDetailsResult>> list(#ModelAttribute #ApiParam("请求参数") GeneralEnter enter) {
return new Response<>(orderService.getOrderList(enter));
}
#GetMapping(value = "/details")
#ApiOperation(value = "Order Details", response = OrderDetailsResult.class)
public Response<OrderDetailsResult> details(#ModelAttribute #ApiParam("请求参数") IdEnter enter) {
return new Response<>(orderService.getOrderDetails(enter));
}
#PostMapping(value = "/delete")
#ApiOperation(value = "delete", response = GeneralResult.class)
public Response<GeneralResult> delete(#ModelAttribute IdEnter enter) {
return new Response<>(orderService.deleteOrder(enter));
}
}
My test file which i'm stuck:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
class OrderControllerTest {
#Autowired
private OrderService service;
private MockMvc mockMvc;
#Test
void shouldAddNewOrder() throws Exception {
}
So i want to have some example to how to test my controller in integration way. Thnks for helps :)
What i've done is below:
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(controllers = OrderControllerTest.class)
class OrderControllerTest {
#MockBean
private OrderService service;
#Autowired
private MockMvc mockMvc;
#Test
void shouldAddNewOrder() throws Exception {
AddUpdateOrderEnter enter = new OrderBuilder()
.orderId(1L)
.orderType(1)
.productId(2L)
.paymentTypeId("STRIPE")
.build();
mockMvc.perform(post("/order/add")
.contentType("application/json"))
.andExpect(status().isOk());
ArgumentCaptor<AddUpdateOrderEnter> orderCaptor = ArgumentCaptor.forClass(AddUpdateOrderEnter.class);
verify(service, times(1)).addOrder(orderCaptor.capture());
assertThat(orderCaptor.getValue().getOrderId()).isEqualTo(1L);
assertThat(orderCaptor.getValue().getOrderType()).isEqualTo(1);
}

How can to mock the method .exchangeToMono().toFuture()?

Tell me how mock the method .exchangeToMono().toFuture()
My example:
public class MyExample {
private final WebClient webClient = WebClient.create();
private CompletableFuture<Result> getValue(Request request) {
return webClient
.post().uri(request.getRequiredParameter(API_URL_PARAM))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.bodyValue(request)
.acceptCharset(StandardCharsets.UTF_8)
.exchangeToMono(rs -> Mono.just(rs.mutate().build()))
.toFuture()
}}
My test but it is not finished I do not understand how to create a mock on
.exchangeToMono(rs -> Mono.just(rs.mutate().build())).toFuture()
public class MyTest {
#Mock
private WebClient webClient;
#Mock
private WebClient.RequestBodyUriSpec requestBodyUriSpecMock;
#Mock
private WebClient.RequestBodySpec requestBodySpecMock;
#SuppressWarnings("rawtypes")
#Mock
private WebClient.RequestHeadersSpec requestHeadersSpecMock;
#Mock
private CompletableFuture<ClientResponse> responseFuture;
#Mock
private Mono<ClientResponse> clientResponseMono;
#Mock
private WebClient.ResponseSpec responseSpecMock;
#Before
public void setUp() {
when(webClient.post()).thenReturn(requestBodyUriSpecMock);
when(requestBodySpecMock.header(anyString(), anyString())).thenReturn(requestBodySpecMock);
when(requestBodySpecMock.acceptCharset(StandardCharsets.UTF_8)).thenReturn(requestBodySpecMock);
when(responseSpecMock.bodyToMono(ClientResponse.class)).thenReturn(clientResponseMono);
}
#Test
public void myTest() throws Exception {
// given
String responseBody = "{name: 'TEST'}";
when(requestBodyUriSpecMock.uri(API_URL_VALUE)).thenReturn(requestBodySpecMock);
when(requestBodySpecMock.bodyValue(responseBody)).thenReturn(requestHeadersSpecMock);
//when(clientResponseMono.block().statusCode()).thenReturn(HttpStatus.OK);
//when(responseFuture.toCompletableFuture()).thenReturn(CompletableFuture.completedFuture(responseSpecMock));}
how to complete a test for a method?

using ConfigurationProperties in test

I have an ApplicationProperties that i use it in my service. When i mock the rest template in my test to test that service it results in java.lang.NullPointerException, when i replace applicationProperties.getBebusiness().getEndPointProvider() with the url, the test passes
#Configuration
#ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
public class ApplicationProperties { ...
}
#Service
public class ProviderServiceImpl implements ProviderService {
private final ApplicationProperties applicationProperties;
private final RestTemplate restTemplate;
public ProviderServiceImpl(ApplicationProperties applicationProperties, RestTemplate restTemplater) {
this.applicationProperties = applicationProperties;
this.restTemplate = restTemplate;
}
#Override
public List <ProviderDTO> getAllProviderFromBebusiness() {
final List <ProviderDTO> result = new ArrayList<>();
final ResponseEntity <String> responseEntity = restTemplate.getForEntity(
applicationProperties.getBebusiness().getEndPointProvider() + "&page=0&size=" + Integer.MAX_VALUE, String.class);
if (responseEntity.getStatusCodeValue() == 200) {}
return result;
}
}
public class ProviderServiceTest {
#Autowired
private ApplicationProperties applicationProperties;
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#InjectMocks
private ProviderServiceImpl providerService;
#Test
public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
String provider = providerInit.buildProviderDTOWithIdFromBebusiness();
ResponseEntity <String> responseEntity = new ResponseEntity <String> (provider, HttpStatus.OK);
when(restTemplate.getForEntity(anyString(), ArgumentMatchers.any(Class.class)))
.thenReturn(responseEntity);
List<ProviderDTO> result = providerService.getAllProviderFromBebusiness();
assertEquals(200, responseEntity.getStatusCodeValue());
}
}
Seems your spring beans are not instantiated. You have to annotate your test class to tell spring it has to initialize its context. Try use #SpringBootTest annotation
You can either use #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) annotation or if you don't want to run Spring Boot context then just mock your configuration class as following:
#BeforeEach // #Before if you're using JUnit4
void setUp() {
Bebusiness bebusiness = mock(Bebusiness.class);
when(applicationProperties.getBebusiness()).thenReturn(bebusiness);
when(bebusiness.getEndPointProvider()).thenReturn("http://localhost:8080");
}
You can use
#TestPropertySource(locations = "/other-location.properties")
Or
#TestPropertySource(properties = "spring.datasource.max-active=30,
spring.datasource.initial-size=5")
This is a exemple : https://www.logicbig.com/tutorials/spring-framework/spring-core/test-property-source-with-inlined-properties.html

org.mockito.exceptions.base.MockitoException: Field 'controller' annotated with #InjectMocks is null

it's my controller method
#RequestMapping(value = "/user", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE, headers = "Accept=application/json")
public #ResponseBody ResponseMessage getUser(#RequestBody AvailableUser uuid) {
return manager.available(uuid);
}
it's my testcontroller
RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:WEB-INF/spring/appServlet/servlet-context.xml" })
public class TestController {
public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
public TestController() {
}
#Mock
private static Manager manager;
#InjectMocks
private Controller controller;
private RMessage msg;
private MockMvc mockMvc;
final ObjectMapper mapper = new ObjectMapper();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void testgetUser() throws Exception
{
AvailableUser availableUser=new AvailableUser();
List<String> lst =new ArrayList<String>();
lst.add("test1");
lst.add("test2");
availableUser.setUuId(lst);
this.mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).content(mapper.writeValueAsString(availableUser)))
.andExpect(status().isOk());
when(manager.available(availableUser)).thenReturn(msg);
}
}
i got error on the #InjectMocks controller is null.
it give me hint for that:
class SomeTest {
#InjectMocks private Foo foo = new Foo();
#Before public void setUp() {
MockitoAnnotations.initMock(this);
}}
but i have do that.
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
i got error in console:
18:16:20,004 DEBUG CacheAwareContextLoaderDelegate:93 - Storing ApplicationContext in cache under key [[MergedContextConfiguration#6483f5ae testClass = TestSurfboardController, locations = '{classpath*:WEB-INF/spring/appServlet/servlet-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
18:16:20,106 DEBUG DirtiesContextTestExecutionListener:94 - After test method: context [DefaultTestContext#5fcd892a testClass = TestSurfboardController, testInstance = com.verizon.surfboard.TestSurfboardController#8b87145, testMethod = testgetUser#TestSurfboardController, testException = org.mockito.exceptions.base.MockitoException: Field 'surfboardController' annotated with #InjectMocks is null.
i am properly apply the #InjectMock on the controller after that i
have done MockitoAnnotations.initMocks(this);
You have to initialize your controller first.
#InjectMocks
private Controller controller = new Controller();
Neither #InjectMocks nor MockMvcBuilders.standaloneSetup will not do it for you.
MockMvcBuilders.standaloneSetup is will throw NPE if you are going to pass null value to it.

Categories