[24.09.10] TIL

yy·2024년 9월 8일

개발일지

목록 보기
100/122

JAVA SPRING BOOT 공부중

테스트 코드

테스트코드 적을 때 주석으로 해놓고 하면 좋음

  • given : 주어진상황

  • when : 이걸 실행했을 때

  • then : 결과값

설명 : given 주어진 상황에서 when 해당 테스트 코드를 실행했을 때 then 결과값이 이렇게 나와야해

assertThrows(IllegalStateException.class, () -> memberService.join(member2))
// 두번째 파라미터를 할 텐데 첫번째 예외가 터질 것을 기대하는 코드


assertEquals(member.getName(), findMember.getName());
// 첫번째와 두번째 파라미터가 동일한지 확인하는 메소드

assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
// 값이 동일한지 확인하는 메소드


단축키

인텔리제이에서 사용하는 단축키가 사람들이 알려주는 단축키와 달라서 곤란했음. 알고보니 키맵에서 이클립스로 설정해놔서 그런거였음.

설정(Ctrl + Alt + s) - 키맵 - 상단을 window로 변경하면됨.



간단한 회원가입 기능

db연결 전임.

package hello.hello_spring.domain;

public class Member {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;

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

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}
package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository {
    private static Map<Long, Member> store = new HashMap<>();

    private static long sequence = 0L;

    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.ofNullable(store.get(id));
    }

    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream().filter(member -> member.getName().equals(name)).findAny();
    }

    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }

    public void clearStore() {
        store.clear();
    }
}
package hello.hello_spring.service;

import hello.hello_spring.domain.Member;
import hello.hello_spring.repository.MemberRepository;
import hello.hello_spring.repository.MemoryMemberRepository;

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

public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    // 회원 가입
    public Long join(Member member) {
        validateDuplicateMember(member);
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("이미 존재하는 회원입니다.");
                });
    }

    // 전체 회원 조회
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }

    // id로 회원 조회
    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }
}



아래는 테스트 코드 (window기준 단축키 Ctrl + Shift + t 쓰면 쉽게 테스트 코드 틀을 만들 수 있음.

package hello.hello_spring.service;

import hello.hello_spring.domain.Member;
import hello.hello_spring.repository.MemoryMemberRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memberRepository;

    @BeforeEach
    public void beforeEach() { // 각 테스트 전에 실행됨. DI 의존성 주입하기
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

    @AfterEach
    public void afterEach() { // 각 테스트 후에 실행. -> repository 비우기
        memberRepository.clearStore();
    }

    @Test
    public void 회원가입() throws Exception {
        //given
        Member member = new Member();
        member.setName("hello");

        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberRepository.findById(saveId).get();
        assertEquals(member.getName(), findMember.getName());
    }

    @Test
    public void 중복회원예외() throws Exception{
        //given
        Member member1 = new Member();
        member1.setName("spring");

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

        //when
        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        //then
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
    }
}
package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class MemoryMemberRepositoryTest {
    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach() {
        repository.clearStore();
    }

    @Test
    public void save() {
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        Member result = repository.findById(member.getId()).get();
        assertThat(result).isEqualTo(member);
    }

    @Test
    public void findByName() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        assertThat(result).isEqualTo(member1);
    }

    @Test
    public void findAll() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring1");
        repository.save(member2);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }

}
package hello.hello_spring.controller;

import hello.hello_spring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}



  • memberController가 memberSerivce를 통해서 데이터를 받고 비즈니스를 수행: 의존성이 있다고 표현

  • @Controller 라는 어노테이션을 두면 스프링 컨테이너가 controller를 관리를 함.

  • @Controller, @Service, @Repository 어노테이션을 적어주면 스프링이 이를 인식해서 스프링빈에 등록시킴.

  • Controller 생성자 위에 @Autowired를 붙이면 자동으로 service를 묶어줌. 그럼 스프링 컨테이너에 있던 멤버서비스를 가지고와서 의존성을 넣어줌.

  • Service도 동일하게 Service 생성자에 @Autowired를 붙여주면 컨테이너에 있던 Repository를 Service에 넣어줌.



스프링 빈을 등록하는 2가지 방법

  1. 컴포넌트 스캔과 자동 의존관계 설정 (자동) (위의 회원코드는 컴포넌트 스캔으로 작성된 방법)
  • @Controller, @Service, @Repository를 넣는 작업 ( 어노테이션 상위로 가면 Component으로 나와있음)

  • 컴포넌트관련 어노테이션이 있으면 스프링이 객체로 각각 스프링 컨테이너에 스프링 빈으로 등록함. 오토와이어드는 각 계층끼리 연결시켜줌.

  • 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 기본적으로 싱글톤으로 등록. (유일하게 하나만 등록해서 공유함) 따라서 같은 스프링 빈이면 모두 같은 인스턴스임.

  • 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용.

  1. 자바 코드로 직접 스프링 빈 등록하기 (수동)
  • 패키지 상위폴더에 config 파일을 만들고, 코드를 적어줘야함.

  • 정형화되지않거나 상황에 따라 구현 클래스를 변경해야하면 설정을 통해 스프링 빈으로 등록.

@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}


DI 주입

  • 생성자 주입 : 생성자를 통해 주입 (가장 좋음 : 의존관계가 실행 중 동적으로 변하는 경우는 거의 없으므로 생성자 주입 권장)

  • 필드 주입: 필드에 @Autowired 하는 것 (별로안좋음)

  • setter 주입 : 아무나 호출될 수 있어.



profile
시간이 걸릴 뿐 내가 못할 건 없다.

0개의 댓글