๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring

Post ์š”์ฒญ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

Post ์š”์ฒญ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

Post ์š”์ฒญ์œผ๋กœ ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋กํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋ฉฐ Junit 5 ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์•Œ์•„๋ณด์ž.

JPA๋ฅผ ์ด์šฉํ•ด MySQL์— User๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค.

model/User.java

package com.vividswan.studymate.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.*;
import java.sql.Timestamp;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 100, unique = true)
    private String username;
    @Column(nullable = false, length = 100)
    private String nickname;
    @Column(nullable = false, length = 50)
    private String email;
    @Column(nullable = false, length = 100)
    private String password;

    @Enumerated(EnumType.STRING)
    private RoleType role;

    @CreationTimestamp
    private Timestamp createDate;
}

controller/userController

package com.vividswan.studymate.controller;

import com.vividswan.studymate.dto.UserJoinDto;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class UserController {
    @GetMapping("join")
    public String joinForm(){
        return "user/joinForm";
    }

}

service/UserService

package com.vividswan.studymate.service;

import com.vividswan.studymate.dto.UserJoinDto;
import com.vividswan.studymate.model.User;
import com.vividswan.studymate.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    @Transactional
    public void join(UserJoinDto userJoinDto) {
        userRepository.save(userJoinDto.toEntity());
    }
}

repositoey/UserRepository

package com.vividswan.studymate.repository;

import com.vividswan.studymate.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

์œ„์™€ ๊ฐ™์€ model, controller, service, repository๋ฅผ ์ž‘์„ฑํ•ด์ค€๋‹ค.

๊ทธ ๋‹ค์Œ ํด๋ผ์ด์–ธํŠธ๋‹จ์—์„œ ์œ ์ € ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ค„ js ํŒŒ์ผ๊ณผ ์Šคํ”„๋ง์—์„œ์˜ api controller๋ฅผ ์ž‘์„ฑํ•ด์ค€๋‹ค.

static/js/user.js

let index ={
    init : function() {
        $("#btn-join").on("click",()=>{
            this.save();
        });
    },
    save : function(){
        let data = {
            username:$("#username").val(),
            password:$("#password").val(),
            email:$("#email").val(),
            nickname:$("#nickname").val(),
        };


        $.ajax({
            type:"POST",
            url:"/api/joinProc",
            data:JSON.stringify(data),
            contentType:"application/json; charset=utf-8"
        })
        .done(function(response){
            if(response.status === 500){
                alert("๋กœ๊ทธ์ธ์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
            }
            else{
                alert("๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
            }
            location.href="/";
        }).fail(function (error){
            alert(JSON.stringify(error));
        });
    }
}
index.init();

api/UserApiController

package com.vividswan.studymate.api;

import com.vividswan.studymate.dto.UserJoinDto;
import com.vividswan.studymate.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class UserApiController {

    private final UserService userService;

    @PostMapping("/api/joinProc")
    public int joinProc(@RequestBody UserJoinDto userJoinDto){
        userService.join(userJoinDto);
        return HttpStatus.OK.value();
    }
}

์œ„์˜ UserApiController์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•ด๋ณด์ž.

UserApiContollerTest.java

package com.vividswan.studymate.api;

import com.vividswan.studymate.dto.UserJoinDto;
import com.vividswan.studymate.model.User;
import com.vividswan.studymate.repository.UserRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
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 org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.List;


@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserApiControllerTest {

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private UserRepository userRepository;

    @AfterEach
    public void tearDown() throws Exception{
        userRepository.deleteAll();
    }

    @Test
    public void joinTest() throws Exception{
        //given
        String username = "vividswan";
        String password = "1234";
        String email = "vividswan@naver.com";
        String nickname = "soohwan";
        UserJoinDto userJoinDto = UserJoinDto.builder()
                .username(username)
                .password(password)
                .email(email)
                .nickname(nickname)
                .build();

        String url = "http://localhost:"+port+"/api/joinProc";

        //when
        ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url,userJoinDto,Long.class);

        //then
        Assertions.assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
        Assertions.assertThat(responseEntity.getBody()).isGreaterThan(0L);

        List<User> all = userRepository.findAll();
        Assertions.assertThat(all.get(0).getUsername()).isEqualTo(username);
        Assertions.assertThat(all.get(0).getEmail()).isEqualTo(email);
    }

}

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

์Šคํ”„๋ง๋ถ€ํŠธ๋กœ ๋™์ž‘ํ•˜๋Š” ํ…Œ์ŠคํŠธ์ž„์„ ์„ ์–ธํ•˜๊ณ , ๋žœ๋คํ•œ ํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

@Autowired

private TestRestTemplate restTemplate;

ResponseEntity๋กœ ํฌ์ŠคํŠธ ์š”์ฒญ์„ ํ•˜๊ธฐ ์œ„ํ•ด TestRestTemplate๋ฅผ ์ด์šฉํ•œ๋‹ค.

@AfterEach

public void tearDown() throws Exception{

userRepository.deleteAll();

}

๊ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚˜๋ฉด repository๋ฅผ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์žˆ๊ฒŒ @AfterEach๋กœ ์„ ์–ธํ•œ ๋’ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ง€์›Œ์ฃผ๋„๋ก ํ•œ๋‹ค.

//when

ResponseEntity responseEntity = restTemplate.postForEntity(url,userJoinDto,Long.class);

TestRestTemplate๋กœ ๋žœ๋ค ํฌํŠธ์˜ url์— dto๋ฅผ ๋ณด๋‚ด์ฃผ๊ณ  Long.class์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋ฐ›๋Š”๋‹ค.

Assertions.assertThat

Assertions.assertThat์œผ๋กœ ์—ฐ๊ฒฐ์ƒํƒœ์™€ ์ž๋ฃŒ์˜ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•œ๋‹ค.

์ด ๋•Œ Assertions๋Š” Junit์ด ์•„๋‹Œ assertj๋กœ ์ž„ํดํŠธํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

import org.assertj.core.api.Assertions;