| Spring REST API 비즈니스 로직 적용 및 JUnitParam을 이용한 테스트
JUnitParam 테스트 라이브러리는 JUnit의 각 Test 메서드에 파라미터를 쓸 수 있게 함으로써 테스트 코드량을 줄이고 유지보수를 쉽게 해주는 유용한 라이브러리입니다. 이 JUnitParam 라이브러리를 이용하여 아래와 같은 비즈니스 로직을 적용한 코드를 작성하도록 하겠습니다.
- basePrice 와 maxPrice가 모두 0이면 free = true 그 이외에는 free = false
- location이 null 이거나 문자열의 길이가 0일 때 offline = false 그 외에는 offline = true
모든 소스 코드는 여기에서 보실 수 있습니다.
프로젝트 구조
+---src
| +---main
| | +---java
| | | \---com
| | | \---example
| | | \---springrestapi
| | | | SpringRestApiApplication.java
| | | |
| | | +---common
| | | | ErrorsSerializer.java
| | | | TestDescription.java
| | | |
| | | \---events
| | | Event.java
| | | EventController.java
| | | EventDto.java
| | | EventRepository.java
| | | EventStatus.java
| | | EventValidator.java
| | |
| | \---resources
| | | application.yml
| | |
| | +---static
| | \---templates
의존성 관리
<dependencies>
...
<dependency>
<groupId>pl.pragmatists</groupId>
<artifactId>JUnitParams</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
- JUnitParam을 사용하기 위해서는 위와 같이 의존성을 추가해야 합니다.
테스트 코드
package com.example.springrestapi.events;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(JUnitParamsRunner.class)
public class EventTest {
// ...
@Test
@Parameters
//@Parameters(method = "parametersForTestFree") // You can reference a parameter method directly like leftward
public void testFree(int basePrice, int maxPrice, boolean isFree) {
// Given
Event event = Event.builder().
basePrice(basePrice)
.maxPrice(maxPrice)
.build();
// When
event.update();
// Then
assertThat(event.isFree()).isEqualTo(isFree);
}
private Object[] parametersForTestFree() {
return new Object[] {
new Object[] {0, 0, true},
new Object[] {100, 0, false},
new Object[] {0, 100, false},
};
}
@Test
@Parameters
public void testOffline(String location, boolean isOffline) {
// Given
Event event = Event.builder()
.location("StartUp Factory")
.build();
// When
event.update();
// Then
assertThat(event.isOffline()).isTrue();
}
private Object[] parametersForTestOffline() {
return new Object[] {
new Object[] {"강남", true},
new Object[] {null, false},
new Object[] {" ", false},
};
}
}
- JUnitParams를 적용하여 테스트 코드를 작성한 것을 볼 수 있습니다. @Parameters 어노테이션을 각 테스트에 명시하면 파리미터화 된 입력값을 쓸 수 있습니다.
- 파라미터화된 입력값은 위 코드와 같이 코드 상에 명시해야 하며 parametersFor + [테스트명] 으로 작성하면 자동적으로 [테스트명]으로 작성된 테스트 메서드에 해당 입력값이 매칭되게 됩니다. 또한 @Parameters(method="[테스트명]") 형태로 직정 지정해서 쓸 수 있습니다.
소스 코드
package com.example.springrestapi.events;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* In case of referencing between entities, using default @EqualsAndHashCode stack overflow.
* Therefore, redefine the way of checking equality is the best practice as below.
* Also, you shouldn't use @Data annotation because it uses default @EqualsAndHashCode
*/
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(of = "id")
public class Event {
@Id @GeneratedValue
private Integer id;
private String name;
private String description;
private LocalDateTime beginEnrollmentDateTime;
private LocalDateTime closeEnrollmentDateTime;
private LocalDateTime beginEventDateTime;
private LocalDateTime endEventDateTime;
private String location; // (optional)
private int basePrice; // (optional)
private int maxPrice; // (optional)
private int limitOfEnrollment;
private boolean offline;
private boolean free;
@Enumerated(EnumType.STRING)
private EventStatus eventStatus = EventStatus.DRAFT;
public void update() {
// Update free
if(this.basePrice == 0 && this.maxPrice == 0) {
this.free = true;
} else {
this.free = false;
}
// Update offline
if(this.location == null || this.location.isBlank()) {
this.offline = false;
} else {
this.offline = true;
}
}
}
- 위에서 언급한 비즈니스 로직을 적용한 엔티티 클래스입니다.
package com.example.springrestapi.events;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
import java.net.URI;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
@Controller
@RequestMapping(value = "/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public class EventController {
@Autowired
EventRepository eventRepository;
@Autowired
ModelMapper modelMapper;
@Autowired
EventValidator eventValidator;
@PostMapping
public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto, Errors errors) {
if(errors.hasErrors()) {
return ResponseEntity.badRequest().body(errors);
}
eventValidator.validate(eventDto, errors);
if(errors.hasErrors()) {
return ResponseEntity.badRequest().body(errors);
}
Event event = modelMapper.map(eventDto, Event.class);
event.update();
Event newEvent = this.eventRepository.save(event);
URI createdURI = linkTo(EventController.class).slash(newEvent.getId()).toUri();
return ResponseEntity.created(createdURI).body(newEvent);
}
}
- HTTP 요청 안에 포함된 데이터들을 Event 객체로 역직렬화한 다음 Event 객체의 update 메서드를 이용해 비즈니스 로직을 적용한 모습입니다.
결과 화면
참조: https://www.inflearn.com/course/spring_rest-api/#
소스 코드 : https://github.com/engkimbs/spring-rest-api
'Spring > Spring Rest API' 카테고리의 다른 글
[Spring REST API #10] Spring REST Docs 소개 및 적용 (0) | 2019.05.31 |
---|---|
[Spring REST API #9] 스프링 HATEOAS 개념 및 적용 (3) | 2019.05.29 |
[Spring REST API #7] Spring REST API Bad Request 처리 및 에러 응답 메세지 보내기 (0) | 2019.05.27 |
[Spring REST API #6] Spring REST API Bad Request 처리 (0) | 2019.05.26 |
[Spring REST API #5] Spring REST API 입력값 제한하기 및 에러 발생 처리 (0) | 2019.05.26 |
이 글을 공유하기