{"id":3688,"date":"2021-10-31T15:50:40","date_gmt":"2021-10-31T06:50:40","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=3688"},"modified":"2021-10-31T15:58:11","modified_gmt":"2021-10-31T06:58:11","slug":"spring-boot-test-%ec%83%98%ed%94%8c-%ec%bd%94%eb%93%9c","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=3688","title":{"rendered":"Spring Boot Test \uc0d8\ud50c \ucf54\ub4dc"},"content":{"rendered":"<h1>Spring Boot Test \uc0d8\ud50c \ucf54\ub4dc<\/h1>\n<p>Spring Boot Test \ud074\ub798\uc2a4\ub97c \uc0dd\uc131\ud560 \ub54c\ub9c8\ub2e4 \ubc18\ubcf5\uc801\uc73c\ub85c \uc0bd\uc9c8\uc744 \ud558\uc5ec,<br \/>\n\uc0d8\ud50c \ucf54\ub4dc\ub97c \uc801\uc5b4 \ub193\ub294\ub2e4.<\/p>\n<h2>Test Class<\/h2>\n<p><code>org.junit.jupiter.api.Test<\/code> \uac00 \uc784\ud3ec\ud2b8 \ub418\uc5b4 \uc788\ub294\uc9c0 \ud655\uc778\ud55c\ub2e4.<br \/>\nIntelliJ \uac00 \uc5c4\ud55c \ud074\ub798\uc2a4\ub97c \uc784\ud3ec\ud2b8\ud574\uc11c \uace0\uc0dd\uc774 \ub9ce\ub2e4.<\/p>\n<pre><code class=\"language-java\">package kr.pe.skyer9.mgapiserver.web;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\n\/\/ ......\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.client.TestRestTemplate;\nimport org.springframework.boot.web.server.LocalServerPort;\n\/\/ ......\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class UserInfoControllerTest {\n\n    @LocalServerPort\n    private int port;\n\n    HttpHeaders headers;\n    ObjectMapper mapper;\n\n    @Autowired\n    private TestRestTemplate restTemplate;\n\n    @BeforeEach\n    public void setUp() {\n\n        mapper = new ObjectMapper();\n        mapper.registerModule(new JavaTimeModule());\n\n        headers = new HttpHeaders();\n    }\n\n    @Test\n    public void createNewUser() throws URISyntaxException, JsonProcessingException {\n\n        \/\/ given\n        String key_uuid = Util.getRandomString(32);\n\n        URI uri = new URI(getBaseUrl() + &quot;create&quot;);\n        UserInfoDto dto = new UserInfoDto();\n        dto.setKeyUuid(key_uuid);\n        HttpEntity&lt;UserInfoDto&gt; request = new HttpEntity&lt;&gt;(dto);\n\n        \/\/ when\n        ResponseEntity&lt;String&gt; result = this.restTemplate.exchange(uri, HttpMethod.POST, request, String.class);\n\n        \/\/ then\n        assertEquals(200, result.getStatusCodeValue());\n        ApiResponseWithData apiResponseWithData = mapper.readValue(result.getBody(), ApiResponseWithData.class);\n        UserInfoDto saved = mapper.convertValue(apiResponseWithData.getData(), UserInfoDto.class);\n        assertEquals(key_uuid, saved.getKeyUuid());\n    }\n\n    @Test\n    public void updateUser() throws URISyntaxException, JsonProcessingException {\n        \/\/ given\n        String accessToken = &quot;CvMgV52Uz8tHj8HaX644TjXXXXXXXXXX&quot;;\n        String key_uuid = &quot;rMPzBha4d9JXaXXXXXXXXXXXXXXXXX&quot;;\n        String userName = &quot;Lee San&quot;;\n        String userEmail = &quot;skyer9@gmail.com&quot;;\n\n        URI uri = new URI(getBaseUrl() + &quot;update&quot;);\n        UserInfoDto dto = new UserInfoDto();\n        dto.setKeyUuid(key_uuid);\n        dto.setUserName(userName);\n        dto.setAccessToken(accessToken);\n\n        \/\/ when\n        headers.add(Constant.X_Authorization, accessToken);\n        HttpEntity&lt;UserInfoDto&gt; request = new HttpEntity&lt;&gt;(dto, headers);\n        ResponseEntity&lt;String&gt; result = this.restTemplate.exchange(uri, HttpMethod.POST, request, String.class);\n\n        \/\/ then\n        assertEquals(200, result.getStatusCodeValue());\n        ApiResponseMessage apiResponseMessage = mapper.readValue(result.getBody(), ApiResponseMessage.class);\n        assertEquals(&quot;000&quot;, apiResponseMessage.getCode());\n    }\n\n    private String getBaseUrl() {\n        return &quot;http:\/\/localhost:&quot; + port + &quot;\/v1\/user\/&quot;;\n    }\n}<\/code><\/pre>\n<h2>RestController<\/h2>\n<pre><code class=\"language-java\">@RestController\n@RequestMapping(&quot;\/v1\/user&quot;)\npublic class UserInfoController extends BaseRestController&lt;UserInfoDto, UserInfo, String, String&gt; {\n\n    public UserInfoController(UserInfoService service) {\n        super(service);\n    }\n\n    @PostMapping(&quot;\/create&quot;)\n    public ResponseEntity&lt;?&gt; createNewUser(@RequestBody UserInfoDto dto) {\n        UserInfoService service = (UserInfoService) super.service;\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, service.createNewUser(dto)));\n    }\n\n    @PostMapping(&quot;\/update&quot;)\n    public ResponseEntity&lt;?&gt; updateUser(@RequestHeader(Constant.X_Authorization) String auth, @RequestBody UserInfoDto dto) {\n        UserInfoService service = (UserInfoService) super.service;\n\n        UserInfo saved = service.get(dto.getKeyUuid(), true);\n        if (!Objects.equals(auth, saved.getAccessToken())) {\n            throw new InvalidAccessTokenException(&quot;\uc798\ubabb\ub41c \uc811\uadfc\uc785\ub2c8\ub2e4.&quot;);\n        }\n        return update(dto.getKeyUuid(), dto);\n    }\n}<\/code><\/pre>\n<pre><code class=\"language-java\">public class BaseRestController&lt;D, E, KD, KE&gt; {\n\n    protected final CustomGenericService&lt;D, E, KD, KE&gt; service;\n\n    public BaseRestController(CustomGenericService&lt;D, E, KD, KE&gt; service) {\n        this.service = service;\n    }\n\n    \/\/ PK \uc790\ub3d9\uc0dd\uc131\n    public ResponseEntity&lt;?&gt; create(D dto) {\n\n        D created = service.create(dto);\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, created));\n    }\n\n    \/\/ PK \uc218\ub3d9\ubd80\uc5ec(PK \uccb4\ud06c)\n    public ResponseEntity&lt;?&gt; create(KD kd, D dto) {\n\n        D created = service.create(kd, dto);\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, created));\n    }\n\n    public ResponseEntity&lt;?&gt; update(KD keyDto, D dto) {\n\n        service.update(keyDto, dto);\n        return ResponseEntity.ok(new ApiResponseMessage(ResponseCode.OK));\n    }\n\n    public ResponseEntity&lt;?&gt; select(KD keyDto) {\n\n        D dto = service.select(keyDto);\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, dto));\n    }\n\n    public ResponseEntity&lt;?&gt; search(Map&lt;String, String&gt; params) {\n\n        SearchResponseDto searchResponseDto = service.search(params);\n\n        return ResponseEntity.ok(\n                new ApiResponseWithPaging(ResponseCode.OK,\n                        searchResponseDto.getResults(),\n                        searchResponseDto.getPageable(),\n                        searchResponseDto.getTotalCount()\n                )\n        );\n    }\n}<\/code><\/pre>\n<h2>CustomGenericService<\/h2>\n<pre><code class=\"language-java\">public abstract class CustomGenericService&lt;D, E, KD, KE&gt; {\n\n    protected JpaRepository&lt;E, KE&gt; repository;\n    protected final String title;\n\n    public CustomGenericService(JpaRepository&lt;E, KE&gt; repository, String title) {\n\n        this.repository = repository;\n        this.title = title;\n    }\n\n    \/\/ \uc0dd\uc131\n    @Transactional\n    public D create(D d) {\n\n        E e = newEntity();\n        updateFromDto(d, e);\n\n        return toDto(repository.save(e));\n    }\n\n    \/\/ \uccb4\ud06c \ubc0f \uc0dd\uc131\n    @Transactional\n    public D create(KD id, D d) throws DataExistsException {\n\n        KE ke = toKeyEntity(id);\n\n        if (get(ke, false) != null) {\n            throw new DataExistsException(title + &quot;\uc774(\uac00) \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4.&quot;);\n        }\n\n        E e = newEntity(ke);\n        updateFromDto(d, e);\n\n        return toDto(repository.save(e));\n    }\n\n    \/\/ \uc218\uc815\n    @Transactional\n    public void update(KD id, D d) {\n\n        E e = get(toKeyEntity(id), true);\n        updateFromDto(d, e);\n        repository.save(e);\n    }\n\n    \/\/ \uc218\uc815 \ub610\ub294 \uc0dd\uc131\n    @Transactional\n    public void updateOrCreate(KD id, D d) {\n\n        E e = get(toKeyEntity(id));\n        updateFromDto(d, e);\n        repository.save(e);\n    }\n\n    \/\/ DTO \uc870\ud68c\n    @Transactional(readOnly = true)\n    public D select(KD id) {\n\n        return toDto(get(toKeyEntity(id), true));\n    }\n\n    \/\/ Entity \ubc18\ud658\n    @Transactional\n    public E get(KE id, boolean throwExceptionIfNotExists) {\n\n        E e = repository.findById(id).orElse(null);\n\n        if (throwExceptionIfNotExists &amp;&amp; (e == null)) {\n            throw new DataNotFoundException(title + &quot;\uc774(\uac00) \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.&quot;);\n        } else {\n            return e;\n        }\n    }\n\n    @Transactional\n    public E get(KE id) {\n        Optional&lt;E&gt; o = repository.findById(id);\n        return o.orElseGet(() -&gt; newEntity(id));\n    }\n\n    public abstract SearchResponseDto search(Map&lt;String, String&gt; params);\n\n    protected List&lt;D&gt; toDto(List&lt;E&gt; lst) {\n\n        return lst.stream().map(this::toDto).collect(Collectors.toList());\n    }\n\n    protected abstract D toDto(E e);\n    protected abstract E toEntity(D e);\n    \/\/ protected abstract KD toKeyDto(KE e);\n    protected abstract KE toKeyEntity(KD e);\n    protected abstract void updateFromDto(D d, E e);\n    protected abstract E newEntity();\n    protected abstract E newEntity(KE e);\n}<\/code><\/pre>\n<h2>ApiResponseMessage<\/h2>\n<pre><code class=\"language-java\">@ToString\n@Getter\n@Setter\n@NoArgsConstructor\npublic class ApiResponseMessage implements Serializable {\n    private String code;\n    private String message;\n\n    public ApiResponseMessage(ResponseCode responseCode) {\n        this.code = responseCode.getKey();\n        this.message = responseCode.getTitle();\n    }\n\n    public ApiResponseMessage(ResponseCode responseCode, String message) {\n        this.code = responseCode.getKey();\n        this.message = message;\n    }\n}<\/code><\/pre>\n<h2>ApiResponseWithData<\/h2>\n<pre><code class=\"language-java\">@ToString\n@Getter\n@Setter\n@NoArgsConstructor\npublic class ApiResponseWithData extends ApiResponseMessage implements Serializable {\n\n    private Object data;\n\n    public ApiResponseWithData(ResponseCode responseCode, Object data) {\n        super(responseCode);\n\n        this.data = data;\n    }\n}<\/code><\/pre>\n<h2>ApiResponseWithPaging<\/h2>\n<pre><code class=\"language-java\">@ToString\n@Getter\n@Setter\n@NoArgsConstructor\npublic class ApiResponseWithPaging extends ApiResponseWithData implements Serializable {\n\n    private ApiResponsePaging paging;\n\n    public ApiResponseWithPaging(ResponseCode responseCode, Object data) {\n        super(responseCode, data);\n\n        this.paging = ApiResponsePaging.builder()\n                .pageNo(0)\n                .pageSize(Constant.DEFAULT_PAGE_SIZE_10)\n                .totalCount(0)\n                .build();\n    }\n\n    public ApiResponseWithPaging(ResponseCode responseCode, List&lt;Object&gt; data, Pageable pageable, int totalCount) {\n        super(responseCode, data);\n\n        this.paging = ApiResponsePaging.builder()\n                .pageNo(pageable.getPageNumber())\n                .pageSize(pageable.getPageSize())\n                .totalCount(totalCount)\n                .build();\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Spring Boot Test \uc0d8\ud50c \ucf54\ub4dc Spring Boot Test \ud074\ub798\uc2a4\ub97c \uc0dd\uc131\ud560 \ub54c\ub9c8\ub2e4 \ubc18\ubcf5\uc801\uc73c\ub85c \uc0bd\uc9c8\uc744 \ud558\uc5ec, \uc0d8\ud50c \ucf54\ub4dc\ub97c \uc801\uc5b4 \ub193\ub294\ub2e4. Test Class org.junit.jupiter.api.Test \uac00 \uc784\ud3ec\ud2b8 \ub418\uc5b4 \uc788\ub294\uc9c0 \ud655\uc778\ud55c\ub2e4. IntelliJ \uac00 \uc5c4\ud55c \ud074\ub798\uc2a4\ub97c \uc784\ud3ec\ud2b8\ud574\uc11c \uace0\uc0dd\uc774 \ub9ce\ub2e4. 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; \/\/ &#8230;&#8230; 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;\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=3688\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29],"tags":[],"class_list":["post-3688","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-5"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3688","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3688"}],"version-history":[{"count":4,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3688\/revisions"}],"predecessor-version":[{"id":3692,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3688\/revisions\/3692"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3688"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3688"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3688"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}