TDD - showMeTheMoneyPrac/BE_Repo GitHub Wiki

1๏ธโƒฃ TDD ๋„์ž… ์ด์œ 

Test Driven Development ์˜ ์•ฝ์ž๋กœ ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

๊ธฐํš์ด ์™„์„ฑ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๊ฐœ๋ฐœ์— ๋“ค์–ด ๊ฐ”๊ธฐ ๋•Œ๋ฌธ์— ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜๊ณ , ์ด์— ๋”ฐ๋ผ์„œ ์š”๊ตฌ ์‚ฌํ•ญ ๋ณ€๊ฒฝ์‹œ๋‚˜ ์„ฑ๋Šฅ ๊ฐœ์„ ์„ ์œ„ํ•œ ๋ฆฌํŒฉํ† ๋ง ์‹œ์— side effect๋ฅผ ๊ณ ๋ ค ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„์ž…ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

2๏ธโƒฃ ํ™œ์šฉ ๋ฐฉ๋ฒ•

  1. Test Tool๋กœ๋Š” JUnit4๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.
  2. ์ •๋ฆฌ๋œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐ API ํ˜ธ์ถœ์‹œ์— ์ ์ ˆํ•œ ๊ฒฐ๊ณผ๊ฐ’์„ ์–ป๋Š”์ง€๋ฅผ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์ฆ๋ช…ํ•˜๋ฉฐ ๊ฐœ๋ฐœํ•˜์˜€๋‹ค.
  3. given // when // then ๋ฐฉ์‹์„ ์ ์šฉํ•˜์—ฌ ๋ช…ํ™•ํ•œ ๋ชฉํ‘œ๋ฅผ ์ •ํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class CartServiceTest {

    @Autowired
    CartRepository cartRepository;
    @Autowired
    CartService cartService;
    @Autowired
    ProductRepository productRepository;
    @Autowired
    MemberRepository memberRepository;
    @Autowired
    ImgRepository imgRepository;

    @Test
    public void ์žฅ๋ฐ”๊ตฌ๋‹ˆ_๋‹ด๊ธฐ_์„ฑ๊ณต() throws Exception{
        //given
        Member member1 = new Member(
                "[email protected]",
                "์ •์š”ํ•œ1",
                "์šฐ๋ฆฌ์ง‘1",
                "passworddd",
                100000);
        memberRepository.save(member1);

        Member member2 = new Member(
                "[email protected]",
                "์ •์š”ํ•œ2",
                "์šฐ๋ฆฌ์ง‘2",
                "passworddd",
                0);
        memberRepository.save(member2);

        Product product1 = Product.builder()
                .category("์นดํ…Œ๊ณ ๋ฆฌ")
                .detail("์„ค๋ช…1")
                .reviewCnt(0)
                .price(20000)
                .title("ํƒ€์ดํ‹€")
                .build();
        productRepository.save(product1);

        Product product2 = Product.builder()
                .category("์นดํ…Œ๊ณ ๋ฆฌ")
                .detail("์„ค๋ช…2")
                .reviewCnt(0)
                .price(40000)
                .title("ํƒ€์ดํ‹€2")
                .build();
        productRepository.save(product2);

        Product product3 = Product.builder()
                .category("์นดํ…Œ๊ณ ๋ฆฌ2")
                .detail("์„ค๋ช…3")
                .reviewCnt(0)
                .price(50000)
                .title("ํƒ€์ดํ‹€3")
                .build();
        productRepository.save(product3);

        List<Img> imgList1 = new ArrayList<>();
        Img img1 = new Img("test1",product1);
        imgList1.add(img1);
        imgRepository.save(img1);

        List<Img> imgList2 = new ArrayList<>();
        Img img2 = new Img("test2",product2);
        imgList2.add(img2);
        imgRepository.save(img2);

        List<Img> imgList3 = new ArrayList<>();
        Img img3 = new Img("test3",product3);
        imgList3.add(img3);
        imgRepository.save(img3);

        CartRequestDto.Add dto = new CartRequestDto.Add("์˜ต์…˜",20000,3);
        CartRequestDto.Add dto1 = new CartRequestDto.Add("์˜ต์…˜1",30000,1);
        CartRequestDto.Add dto2 = new CartRequestDto.Add("์˜ต์…˜2",40000,2);
        CartRequestDto.Add dto3 = new CartRequestDto.Add("์˜ต์…˜3",60000,4);

        //when
        String msg = cartService.cartAdd(member1.getNickname(),product1.getId(), dto);
        String msg1 = cartService.cartAdd(member1.getNickname(),product2.getId(), dto1);
        String msg2 = cartService.cartAdd(member2.getNickname(),product1.getId(), dto2);
        String msg3 = cartService.cartAdd(member2.getNickname(),product3.getId(), dto3);

        //then
        assertEquals(msg,"msg : ๋‹ด๊ธฐ ์™„๋ฃŒ");
        assertEquals(msg1,"msg : ๋‹ด๊ธฐ ์™„๋ฃŒ");
        assertEquals(msg2,"msg : ๋‹ด๊ธฐ ์™„๋ฃŒ");
        assertEquals(msg3,"msg : ๋‹ด๊ธฐ ์™„๋ฃŒ");
    }
}

image

3๏ธโƒฃ ๊ธฐ์ˆ ์˜ ์žฅ์ 

  1. ์žฌ์„ค๊ณ„ ์‹œ๊ฐ„์˜ ๋‹จ์ถ•

-ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง€๊ธˆ ๋ฌด์—‡์„ ํ•ด์•ผํ•˜๋Š”์ง€ ๋ถ„๋ช…ํžˆ ์ •์˜ํ•˜๊ณ  ๊ฐœ๋ฐœ์„ ์‹œ์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค. ๋˜ํ•œ ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง์‹œ์— ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ผ๋Š” ๋ฐฉํŒจ๋ฅผ ๊ฐ€์ง€๊ณ  ๊ณผ๊ฐํ•˜๊ฒŒ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

  1. ์„ค๊ณ„์˜ ์™„์„ฑ๋„ ์ฆ๊ฐ€

-์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ž‘์„ฑํ•จ์— ์žˆ์–ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•˜์—ฌ ์ƒ๊ฐํ•˜๊ณ  ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

  1. ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ์ฝ”๋“œ ์ƒ์‚ฐ

-TDD๋Š” ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ ๋ณด์žฅ์„ ๋ช…์‹œํ•˜๋ฏ€๋กœ TDD๋ฅผ ํ†ตํ•œ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ์‹œ ๊ธฐ๋Šฅ ๋ณ„ ์ฒ ์ €ํ•œ ๋ชจ๋“ˆํ™”๊ฐ€ ์ด๋ค„์ง„๋‹ค. ์ด๋Š” ์ข…์†์„ฑ๊ณผ ์˜์กด์„ฑ์ด ๋‚ฎ์€ ๋ชจ๋“ˆ๋กœ ์กฐํ•ฉ๋œ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ ํ•„์š”์— ๋”ฐ๋ผ ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•ด๋„ ์†Œํ”„ํŠธ์›จ์–ด ์ „์ฒด ๊ตฌ์กฐ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

4๏ธโƒฃ ๊ธฐ์ˆ ์˜ ๋‹จ์ 

  1. ์ƒ์‚ฐ์„ฑ์˜ ์ €ํ•˜
  • TDD๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์งœ๋ฉด์„œ ์‹ค์ œ ๊ตฌํ˜„๋„ ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋งŒํผ์˜ ์ถ”๊ฐ€์ ์ธ ๊ฐœ๋ฐœ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ๋‹จ์ˆœํ•œ api์˜ ๊ฒฝ์šฐ ์–ด๋А์ •๋„ ๊ฒฐ๊ณผ๊ฐ€ ์˜ˆ์ƒ์ด ๊ฐ€๋Šฅํ•œ๋ฐ, ์ด๋ฅผ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋งค์šฐ ๋น„ํšจ์œจ์ ์ผ ์ˆ˜๋„ ์žˆ๋‹ค.

5๏ธโƒฃ ์ถ”๊ฐ€์  ๋ฐฉ์•ˆ์€?

  • MockMvc ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ข€ ๋” ํŽธ๋ฆฌํ•œ test ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค.
MockMvc๋Š” ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„์— ๋ฐฐํฌํ•˜์ง€ ์•Š๊ณ  ํ…Œ์ŠคํŠธ์šฉ MVCํ™˜๊ฒฝ์„ ๋งŒ๋“ค์–ด
์š”์ฒญ ๋ฐ ์ „์†ก, ์‘๋‹ต๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ฃผ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋‹ค.

mockMvc์˜ ๋ฉ”์†Œ๋“œ 
1) perform()

์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋กœ ResultActions ๊ฐ์ฒด๋ฅผ ๋ฐ›์œผ๋ฉฐ, ResultActions ๊ฐ์ฒด๋Š” ๋ฆฌํ„ด ๊ฐ’์„ ๊ฒ€์ฆํ•˜๊ณ  ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” andExcpect() ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค.
 
2) get("/mock/**")

HTTP ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ( get(), post(), put(), delete() )
์ธ์ž๋กœ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.

3) params(info)

ํ‚ค=๊ฐ’์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ๋Š” params()๋ฅผ, ํ•˜๋‚˜์ผ ๋•Œ์—๋Š” param()์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
 
4) andExpect()

์‘๋‹ต์„ ๊ฒ€์ฆํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
์ƒํƒœ ์ฝ”๋“œ ( status() )
๋ฉ”์†Œ๋“œ ์ด๋ฆ„ : ์ƒํƒœ์ฝ”๋“œ
isOk() : 200
isNotFound() : 404
isMethodNotAllowed() : 405
isInternalServerError() : 500
is(int status) : status ์ƒํƒœ ์ฝ”๋“œ
๋ทฐ ( view() )
๋ฆฌํ„ดํ•˜๋Š” ๋ทฐ ์ด๋ฆ„์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
ex. view().name("go") : ๋ฆฌํ„ดํ•˜๋Š” ๋ทฐ ์ด๋ฆ„์ด go์ธ๊ฐ€?
๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ( redirect() )
๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์‘๋‹ต์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
ex. redirectUrl("/go") : '/go'๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋˜์—ˆ๋Š”๊ฐ€?
๋ชจ๋ธ ์ •๋ณด ( model() )
์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ €์žฅํ•œ ๋ชจ๋ธ๋“ค์˜ ์ •๋ณด ๊ฒ€์ฆ
์‘๋‹ต ์ •๋ณด ๊ฒ€์ฆ ( content() )
์‘๋‹ต์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฒ€์ฆํ•ด์ค๋‹ˆ๋‹ค.
 
5) andDo(print())

์š”์ฒญ/์‘๋‹ต ์ „์ฒด ๋ฉ”์„ธ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  ๋ฌธํ—Œ

https://wooaoe.tistory.com/33 https://mangkyu.tistory.com/182 https://shinsunyoung.tistory.com/52 https://velog.io/@jkijki12/Spring-MockMvc

โš ๏ธ **GitHub.com Fallback** โš ๏ธ