Spring Boot Test 샘플 코드

By | 2021년 10월 31일
Table of Content

Spring Boot Test 샘플 코드

Spring Boot Test 클래스를 생성할 때마다 반복적으로 삽질을 하여,
샘플 코드를 적어 놓는다.

Test Class

org.junit.jupiter.api.Test 가 임포트 되어 있는지 확인한다.
IntelliJ 가 엄한 클래스를 임포트해서 고생이 많다.

package kr.pe.skyer9.mgapiserver.web;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
// ......
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
// ......
import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserInfoControllerTest {

    @LocalServerPort
    private int port;

    HttpHeaders headers;
    ObjectMapper mapper;

    @Autowired
    private TestRestTemplate restTemplate;

    @BeforeEach
    public void setUp() {

        mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());

        headers = new HttpHeaders();
    }

    @Test
    public void createNewUser() throws URISyntaxException, JsonProcessingException {

        // given
        String key_uuid = Util.getRandomString(32);

        URI uri = new URI(getBaseUrl() + "create");
        UserInfoDto dto = new UserInfoDto();
        dto.setKeyUuid(key_uuid);
        HttpEntity<UserInfoDto> request = new HttpEntity<>(dto);

        // when
        ResponseEntity<String> result = this.restTemplate.exchange(uri, HttpMethod.POST, request, String.class);

        // then
        assertEquals(200, result.getStatusCodeValue());
        ApiResponseWithData apiResponseWithData = mapper.readValue(result.getBody(), ApiResponseWithData.class);
        UserInfoDto saved = mapper.convertValue(apiResponseWithData.getData(), UserInfoDto.class);
        assertEquals(key_uuid, saved.getKeyUuid());
    }

    @Test
    public void updateUser() throws URISyntaxException, JsonProcessingException {
        // given
        String accessToken = "CvMgV52Uz8tHj8HaX644TjXXXXXXXXXX";
        String key_uuid = "rMPzBha4d9JXaXXXXXXXXXXXXXXXXX";
        String userName = "Lee San";
        String userEmail = "skyer9@gmail.com";

        URI uri = new URI(getBaseUrl() + "update");
        UserInfoDto dto = new UserInfoDto();
        dto.setKeyUuid(key_uuid);
        dto.setUserName(userName);
        dto.setAccessToken(accessToken);

        // when
        headers.add(Constant.X_Authorization, accessToken);
        HttpEntity<UserInfoDto> request = new HttpEntity<>(dto, headers);
        ResponseEntity<String> result = this.restTemplate.exchange(uri, HttpMethod.POST, request, String.class);

        // then
        assertEquals(200, result.getStatusCodeValue());
        ApiResponseMessage apiResponseMessage = mapper.readValue(result.getBody(), ApiResponseMessage.class);
        assertEquals("000", apiResponseMessage.getCode());
    }

    private String getBaseUrl() {
        return "http://localhost:" + port + "/v1/user/";
    }
}

RestController

@RestController
@RequestMapping("/v1/user")
public class UserInfoController extends BaseRestController<UserInfoDto, UserInfo, String, String> {

    public UserInfoController(UserInfoService service) {
        super(service);
    }

    @PostMapping("/create")
    public ResponseEntity<?> createNewUser(@RequestBody UserInfoDto dto) {
        UserInfoService service = (UserInfoService) super.service;

        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, service.createNewUser(dto)));
    }

    @PostMapping("/update")
    public ResponseEntity<?> updateUser(@RequestHeader(Constant.X_Authorization) String auth, @RequestBody UserInfoDto dto) {
        UserInfoService service = (UserInfoService) super.service;

        UserInfo saved = service.get(dto.getKeyUuid(), true);
        if (!Objects.equals(auth, saved.getAccessToken())) {
            throw new InvalidAccessTokenException("잘못된 접근입니다.");
        }
        return update(dto.getKeyUuid(), dto);
    }
}
public class BaseRestController<D, E, KD, KE> {

    protected final CustomGenericService<D, E, KD, KE> service;

    public BaseRestController(CustomGenericService<D, E, KD, KE> service) {
        this.service = service;
    }

    // PK 자동생성
    public ResponseEntity<?> create(D dto) {

        D created = service.create(dto);

        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, created));
    }

    // PK 수동부여(PK 체크)
    public ResponseEntity<?> create(KD kd, D dto) {

        D created = service.create(kd, dto);

        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, created));
    }

    public ResponseEntity<?> update(KD keyDto, D dto) {

        service.update(keyDto, dto);
        return ResponseEntity.ok(new ApiResponseMessage(ResponseCode.OK));
    }

    public ResponseEntity<?> select(KD keyDto) {

        D dto = service.select(keyDto);

        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, dto));
    }

    public ResponseEntity<?> search(Map<String, String> params) {

        SearchResponseDto searchResponseDto = service.search(params);

        return ResponseEntity.ok(
                new ApiResponseWithPaging(ResponseCode.OK,
                        searchResponseDto.getResults(),
                        searchResponseDto.getPageable(),
                        searchResponseDto.getTotalCount()
                )
        );
    }
}

CustomGenericService

public abstract class CustomGenericService<D, E, KD, KE> {

    protected JpaRepository<E, KE> repository;
    protected final String title;

    public CustomGenericService(JpaRepository<E, KE> repository, String title) {

        this.repository = repository;
        this.title = title;
    }

    // 생성
    @Transactional
    public D create(D d) {

        E e = newEntity();
        updateFromDto(d, e);

        return toDto(repository.save(e));
    }

    // 체크 및 생성
    @Transactional
    public D create(KD id, D d) throws DataExistsException {

        KE ke = toKeyEntity(id);

        if (get(ke, false) != null) {
            throw new DataExistsException(title + "이(가) 이미 존재합니다.");
        }

        E e = newEntity(ke);
        updateFromDto(d, e);

        return toDto(repository.save(e));
    }

    // 수정
    @Transactional
    public void update(KD id, D d) {

        E e = get(toKeyEntity(id), true);
        updateFromDto(d, e);
        repository.save(e);
    }

    // 수정 또는 생성
    @Transactional
    public void updateOrCreate(KD id, D d) {

        E e = get(toKeyEntity(id));
        updateFromDto(d, e);
        repository.save(e);
    }

    // DTO 조회
    @Transactional(readOnly = true)
    public D select(KD id) {

        return toDto(get(toKeyEntity(id), true));
    }

    // Entity 반환
    @Transactional
    public E get(KE id, boolean throwExceptionIfNotExists) {

        E e = repository.findById(id).orElse(null);

        if (throwExceptionIfNotExists && (e == null)) {
            throw new DataNotFoundException(title + "이(가) 존재하지 않습니다.");
        } else {
            return e;
        }
    }

    @Transactional
    public E get(KE id) {
        Optional<E> o = repository.findById(id);
        return o.orElseGet(() -> newEntity(id));
    }

    public abstract SearchResponseDto search(Map<String, String> params);

    protected List<D> toDto(List<E> lst) {

        return lst.stream().map(this::toDto).collect(Collectors.toList());
    }

    protected abstract D toDto(E e);
    protected abstract E toEntity(D e);
    // protected abstract KD toKeyDto(KE e);
    protected abstract KE toKeyEntity(KD e);
    protected abstract void updateFromDto(D d, E e);
    protected abstract E newEntity();
    protected abstract E newEntity(KE e);
}

ApiResponseMessage

@ToString
@Getter
@Setter
@NoArgsConstructor
public class ApiResponseMessage implements Serializable {
    private String code;
    private String message;

    public ApiResponseMessage(ResponseCode responseCode) {
        this.code = responseCode.getKey();
        this.message = responseCode.getTitle();
    }

    public ApiResponseMessage(ResponseCode responseCode, String message) {
        this.code = responseCode.getKey();
        this.message = message;
    }
}

ApiResponseWithData

@ToString
@Getter
@Setter
@NoArgsConstructor
public class ApiResponseWithData extends ApiResponseMessage implements Serializable {

    private Object data;

    public ApiResponseWithData(ResponseCode responseCode, Object data) {
        super(responseCode);

        this.data = data;
    }
}

ApiResponseWithPaging

@ToString
@Getter
@Setter
@NoArgsConstructor
public class ApiResponseWithPaging extends ApiResponseWithData implements Serializable {

    private ApiResponsePaging paging;

    public ApiResponseWithPaging(ResponseCode responseCode, Object data) {
        super(responseCode, data);

        this.paging = ApiResponsePaging.builder()
                .pageNo(0)
                .pageSize(Constant.DEFAULT_PAGE_SIZE_10)
                .totalCount(0)
                .build();
    }

    public ApiResponseWithPaging(ResponseCode responseCode, List<Object> data, Pageable pageable, int totalCount) {
        super(responseCode, data);

        this.paging = ApiResponsePaging.builder()
                .pageNo(pageable.getPageNumber())
                .pageSize(pageable.getPageSize())
                .totalCount(totalCount)
                .build();
    }
}

답글 남기기