[Spring Boot] Service ๊ฐœ๋ฐœ ๋ฐ Test Case ์ž‘์„ฑ

2021. 8. 11. 08:00ใ†Back-End ์ž‘์—…์‹ค/Spring Framework

728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š”? ์ฃผ๋‹ˆํ•˜๋ž‘ ์ž…๋‹ˆ๋‹ค.

์ฃผ๋‹ˆํ•˜๋ž‘์€ Spring Boot์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

์˜ค๋Š˜์€ ํšŒ์› ์„œ๋น„์Šค ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•๊ณผ Test Case ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณต๋ถ€ ํ•ด ๋ณด๋„๋ก ํ•  ๊ฒƒ์ด์—์š”.

๋ฐ”๋กœ ์‹œ์ž‘ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

 

์ฝ”๋“œ์— ๊ด€๋ จํ•œ ๋‚ด์šฉ์€ ์ฃผ๋‹ˆํ•˜๋ž‘์˜ Github์—์„œ ํ™•์ธ ํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 

 


 

๐Ÿ“‹ ๋ชฉ์ฐจ


01.[Spring Boot] thymeleaf์™€ Spring Boot
02.[Spring Boot] Spring Web ๊ฐœ๋ฐœ ๊ธฐ์ดˆ
03.[Spring Boot] ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - Backend
04.[Spring Boot] Service ๊ฐœ๋ฐœ ๋ฐ Test Case ์ž‘์„ฑ
05.[Spring Boot] Spring Bean๊ณผ ์˜์กด๊ด€๊ณ„
06.[Spring Boot] Java Code๋กœ ์ง์ ‘ Spring Bean ๋“ฑ๋ก
07.[Spring Boot] ๋“ฑ๋ก, ๋ชฉ๋ก ๋ณด๊ธฐ ๊ตฌํ˜„ํ•˜๊ธฐ
08.[Spring Boot] ๊ธฐ์กด ์ฝ”๋“œ ์† ์•ˆ๋Œ€๊ณ , ์„ค์ •์œผ๋กœ ๊ตฌํ˜„ Class ๋ณ€๊ฒฝ
09.[Spring Boot] ํ†ตํ•ฉ Test
10.[Spring Boot] JPA
11.[Spring Boot] Spring Data JPA
12.[Spring Boot] AOP

 

 


 

 

 

๐Ÿ“Œ ํšŒ์› ์„œ๋น„์Šค ๊ฐœ๋ฐœ


Service ์ชฝ์€ ๋น„์ฆˆ๋‹ˆ์Šค ์šฉ์–ด์— ๋งž๊ฒŒ ์ด๋ฆ„ ๋“ฑ์„ ์ ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฑฐ ๋จผ์ € ์•Œ๊ณ  ๊ฐ€์š” ์šฐ๋ฆฌ!

 

 

MemberService.java

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Optional;

// ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋ฐฉ์‹์˜ Service
// @Service
public class MemberService {   // Service ์ชฝ์€ ๋น„์ฆˆ๋‹ˆ์Šค ์šฉ์–ด์— ๋งž๊ฒŒ ์ด๋ฆ„ ๋“ฑ์„ ์ ์–ด์•ผ ํ•œ๋‹ค.
        // ์•„๋ž˜ ๋‚ด์šฉ์—์„œ repository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , Service Test์—์„œ ๋˜ new๋ฅผ ํ†ตํ•ด Repository๋ฅผ ์ƒ์„ฑํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
//  private final MemoryMemberRepository memberRepository = new MemoryMemberRepository();

    // ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ค€๋‹ค.
    private final MemoryMemberRepository memberRepository;

    // @Service๊ฐ€ ์žˆ๋Š” Service๊ฐ€ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ, @Autowired๊ฐ€ ๋ถ™์€ ์ƒ์„ฑ์ž๋Š” ์Šคํ”„๋ง์ด ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋นˆ์œผ๋กœ ๊ด€๋ฆฌํ•  ๋•Œ, ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ์ด ๋•Œ MemberService๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.
    @Autowired
    public MemberService(MemoryMemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    } // ์ƒ์„ฑ์ž ๋

    // ํšŒ์› ๊ฐ€์ž…
    public Long join(Member member) {
        // ๊ฐ™์€ ์ด๋ฆ„์ด ์žˆ๋Š” ์ค‘๋ณต ํšŒ์› ๊ฐ€์ž… ๋ฐฉ์ง€
//        Optional<Member> result = memberRepository.findByName(member.getName());
//
//        result.ifPresent(memeber -> { // ifPresent๋Š” ํ•ด๋‹น ๊ฐ’์ด Null์ด ์•„๋‹ˆ๊ณ , ์–ด๋–ค ๊ฐ’์ด ์žˆ์œผ๋ฉด ๋™์ž‘ (Option๋กœ ๊ฐ์‹ธ๋ฉด ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
//            throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์› ์ž…๋‹ˆ๋‹ค.");
//        });

        // ์œ„์— ์ฝ”๋“œ ๋ณด๋‹ค ๋” ์ข‹์€ ์ฝ”๋“œ
//        memberRepository.findByName(member.getName()).ifPresent(member1 -> {
//            throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์› ์ž…๋‹ˆ๋‹ค.")
//        });

        // ์œ„์˜ ์ฝ”๋“œ๋ฅผ Methodํ™” ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
        // ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์„ ํƒํ•˜๊ณ , Command + Option + M์„ ๋ˆŒ๋Ÿฌ์ค€๋‹ค.

        validateDuplicationMember(member);      // ์ค‘๋ณต ํšŒ์› ๊ฒ€์ฆ

        memberRepository.save(member);
        return member.getId();
    } // join() ๋

    private void validateDuplicationMember(Member member) {
        // ์œ„์— ์ฝ”๋“œ ๋ณด๋‹ค ๋” ์ข‹์€ ์ฝ”๋“œ
        memberRepository.findByName(member.getName()).ifPresent(member1 -> {
            throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์› ์ž…๋‹ˆ๋‹ค.");
        });
    } // validateDuplicationMember() ๋

    public List<Member> findMembers() {
        return memberRepository.findAll();
    } // findMembers() ๋

    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    } // findOne() ๋

} // Class ๋

 

์ฃผ๋‹ˆํ•˜๋ž‘์ด ์œ„์— ์ฃผ์„์ฒ˜๋ฆฌํ•œ ๋ถ€๋ถ„์ธ 

@Service
public class MemberService {   // Service ์ชฝ์€ ๋น„์ฆˆ๋‹ˆ์Šค ์šฉ์–ด์— ๋งž๊ฒŒ ์ด๋ฆ„ ๋“ฑ์„ ์ ์–ด์•ผ ํ•œ๋‹ค.
        // ์•„๋ž˜ ๋‚ด์šฉ์—์„œ repository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , Service Test์—์„œ ๋˜ new๋ฅผ ํ†ตํ•ด Repository๋ฅผ ์ƒ์„ฑํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
	private final MemoryMemberRepository memberRepository = new MemoryMemberRepository();

์œ„์™€ ๊ฐ™์ด new๋ฅผ ํ†ตํ•ด์„œ Repository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๊ฒƒ์€ ํ•„๋“œ ๋ณ€์ˆ˜์—์„œ repository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ฐจํ›„์— ๋งŒ๋“ค๊ฒŒ ๋  Service Test์—์„œ ๋˜ new๋ฅผ ํ†ตํ•ด Repository๋ฅผ ์ƒ์„ฑํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋œ๋‹ค๋Š” ๋ฌธ์ œ์ธ ๊ฒƒ์ด์—์š”.

๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ํšŒ์› ์„œ๋น„์Šค ์ฝ”๋“œ๋ฅผ DI(Denpendency Injection)์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ณ€๊ฒฝ ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์•„์š”.

public class MemberService {
	private final MemoryMemberRepository memberRepository;
            
    public MemberService(MemoryMemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    } // ์ƒ์„ฑ์ž ๋
} // Class ๋

 

 

MemberServiceTest.java

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memberRepository;

    @BeforeEach
    // Dependency Injection (DI ๊ธฐ๋ฒ•)
    public void beforEach() {   // test๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— MemoryMemberRepository ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์ค€ ๋’ค ๊ทธ ๊ฐ์ฒด๋ฅผ MemoryMemberRepository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ•ด ์ฃผ๋ฉด์„œ ๋„ฃ์–ด์ค€๋‹ค.
        memberRepository = new MemoryMemberRepository();
        // ์ด๋ ‡๊ฒŒ ํ•ด์คŒ์œผ๋กœ MemberService์™€ MemberServiceTest๊ฐ€ ๊ฐ™์€ ๊ฐ์ฒด์˜ MemoryMemberRepository๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
        memberService = new MemberService(memberRepository);
    } // beforEach() ๋

    @AfterEach
    public void afterEach() {
        memberRepository.clearStore();
    } // afterEach() ๋

    @Test
    void ํšŒ์›๊ฐ€์ž…() {

        // given(๋ฌด์—‡์ธ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ)
        Member member = new Member();
        member.setName("JunyHarang");

        // when(์ด๊ฒƒ์„ ์‹คํ–‰ ํ–ˆ์„ ๋•Œ)
        Long saveId = memberService.join(member);

        // then(๊ฒฐ๊ณผ๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์™€์•ผ ํ•œ๋‹ค. (๊ฒ€์ฆ๋ถ€))
        Member findMember = memberService.findOne(saveId).get();
        Assertions.assertThat(member.getName()).isEqualTo(findMember.getName());

    } // ํšŒ์›๊ฐ€์ž… () ๋

    @Test
    public void ์ค‘๋ณตํšŒ์›_์˜ˆ์™ธ() {
        // given
        Member member1 = new Member();
        member1.setName("JunyHarang");

        Member member2 = new Member();
        member2.setName("JunyHarang");

        // when
        memberService.join(member1);

//        try {             // ๋ฐฉ๋ฒ• 1
//            memberService.join(member2);
//            fail("์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.");
//
//        } catch (IllegalStateException e) {
//            // MemberService์˜ Throw ๋ถ€๋ถ„์— Exception ๋ฐœ์ƒ ์‹œ ์ถœ๋ ฅํ•˜๊ณ ์ž ํ–ˆ๋˜ ๋ฌธ๊ตฌ์™€ ๋™์ผํ•˜๊ฒŒ isEqualTo์— ๋„ฃ๋Š”๋‹ค.
//            Assertions.assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์› ์ž…๋‹ˆ๋‹ค.");
//            System.out.println("ํšŒ์› ๊ฐ€์ž… ์ด๋ฆ„ ์ค‘๋ณต์œผ๋กœ ์ธํ•ด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
//        }

        // ๋ฐฉ๋ฒ• 2
        // memberService.join()์— member2๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋กœ์ง์„ ์‹คํ–‰ํ•  ๊ฑด๋ฐ, IllegalStateException๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ์ •์ƒ
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        Assertions.assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์› ์ž…๋‹ˆ๋‹ค.");

        //then
    }

 

์œ„์—์„œ ์‚ฌ์šฉํ•œ @BeforeEach๋Š” ๊ฐ Test ์‹คํ–‰ ์ „์— ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด์—์š”.
ํ…Œ์ŠคํŠธ๊ฐ€ ์„œ๋กœ ์˜ํ–ฅ์ด ์—†๋„๋ก ํ•ญ์ƒ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ , ์˜์กด๊ด€๊ณ„๋„ ๋งบ์–ด์ฃผ๋Š” ์นœ๊ตฌ๋ž๋‹ˆ๋‹ค!

๊ทธ Method์•ˆ์— ์ƒ์„ฑํ•  ๊ฐ์ฒด๋“ค์„ new๋กœ ๋งŒ๋“ค์–ด ์ฃผ๋ฏ€๋กœ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด์—์š”!

 

728x90
๋ฐ˜์‘ํ˜•