1. 컨트롤러 코드
- 멀티 파일과 객체를 같이 받아오는 것은 RequestBody가 아니라 RequestPart로 받아와야함.
- PostMapping 에서 value와 consumes 을 써준 후 뒤에 타입을 아래와 같이 밝혀줘야함.
- value 는 URI 주소 consumes 는 타입
- RequestPart 뒤의 value 값은 받아오는 객체의 이름과 파일이름과 반드시 일치해야함. 그렇지 않으면 찾는 값이 null 이라고 400 오류가 뜸.
@PostMapping(value = "/practicalTemplate",consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
@ResponseStatus(HttpStatus.CREATED)
public PracticalTemplateDto createNewPracticalTemplate(
@RequestPart(value = "practicalTemplate") PracticalTemplateRegistrationDto practicalTemplateRegistrationDto,
@RequestPart(value="multipartFile", required = false) MultipartFile multipartFile
) throws IOException {
return createPracticalTemplateService.practicalTemplate(practicalTemplateRegistrationDto,multipartFile);
}
2. <Spring Boot> content type 'application/octet-stream' not supported 415 오류 해결
1번 처럼 해도 415번 오류가 뜸.
클래스를 하나 만들어서(난 util이라고 만들었음) 아래와 같이 복붙
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import java.lang.reflect.Type;
@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/**
* Converter for support http request with header Content-Type: multipart/form-data
*/
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
그럼 해결~
3. multipartFile 과 requestPart 테스트 코드 짜는 법
당연히 위와 같이 하면 테스트 코드가 터진다...
multipartFile을 mocking해주자
@Test
void create() throws Exception {
MockMultipartFile multipartFile = new MockMultipartFile("multipartFile", "filename.mp4", "video/mp4", "some xml".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("practice", "", "application/json",
("{" +
"\"title\":\"바에서 음료 물어보기\"," +
"\"situation\":\"바에서 말 걸때\"," +
"\"koreanScript\":\"어떤 음료 좋아하세요?\"," +
"\"englishScript\":\"what kind of drink do you like?\"" +
"}").getBytes());
given(createPracticeService.practice(any(),any(),any())).willReturn(
Practice.fake().toDto()
);
mockMvc.perform(MockMvcRequestBuilders.multipart("/practice/new")
.file(multipartFile)
.file(jsonFile)
.requestAttr("userId",1L))
.andExpect(status().isCreated())
.andExpect(content().string(containsString("카페에서 지갑 잃어버렸을때")));
}
}
3. S3 테스트 코드 짜는 법
S3 는 서비스 로직이나 이용해주는 로직에서 mock 만 해주면 된다.
class ClassName {
private S3Uploader s3Uploader;
@BeforeEach
void setUp() {
s3Uploader = mock(S3Uploader.class);
}
예시 코드
class CreatePracticeServiceTest {
private PracticeRepository practiceRepository;
private S3Uploader s3Uploader;
private CreatePracticeService createPracticeService;
@BeforeEach
void setUp() {
practiceRepository = mock(PracticeRepository.class);
s3Uploader = mock(S3Uploader.class);
createPracticeService = new CreatePracticeService(practiceRepository,s3Uploader);
}
@Test
void createPractice() throws IOException {
given(practiceRepository.save(any())).willReturn(Practice.fake());
MockMultipartFile mockMultipartFile = new MockMultipartFile("multipartFile","filename.txt", "text/plain", "some xml".getBytes());
createPracticeService.practice(1L, PracticeRegistrationDto.fake(),mockMultipartFile);
verify(practiceRepository).save(any());
}
}
댓글