[입문] 메모리 리포지토리

본 글은 김영한님의 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술" 강의를 정리한 것입니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8


메모리를 repository로 하는 비즈니스 로직

1. 비즈니스 요구사항

리포지토리 - DAO 역할
도메인 - DTO 역할


2. 도메인, 리포지토리, 서비스, 컨트롤러의 구현

  • domain

도메인은 Servlet-JSP에서 DTO와 유사하다.
DB 테이블 명을 클래스 이름으로. 컬럼을 변수로. getter/setter를 메서드로 갖는다.

  • repository

리포지토리는 Servlet-JSP에서 DAO와 유사하다. Insert, Update, Delete, Select 등이 구현된다.
단 DB가 변경될 것을 대비하여 기본 리포지토리를 인터페이스로 생성하고, DB에 따른 구현클래스를 생성한다. 다형성을 활용해 상위 인터페이스를 객체로 사용하면 DB가 변경되도 구현 클래스만 바꾸면 된다.

MemberRepository 인터페이스. 선언만 되어있다.

MemoryMemberRepository 클래스. 상위 인터페이스의 로직이 실제로 구현된다. 구현 초기에는 DB 연동 전에 메모리 내에서 Map으로 구현하여 로직을 확인한다.

  • service

Repository 객체를 생성. 비즈니스 로직을 활용해 실제 원하는 서비스를 구현한다.


3. 테스트 코드

테스트 코드란?
작성한 코드가 의도한 대로 구동되는지 확인하는 코드. 예시는 Repository와 Service의 비즈니스로직이 원하는 대로 수행되는지 확인하는 코드이다. 인텔리제이에서 Ctrl+Shift+T 로 생성한다. given(주어진 상황) - when(동작 수행) - then(원하는 결과와 비교)의 세 단계로 이루어진다. 모든 테스트는 독립적으로 수행되어야 하기에, @AfterEach를 통해 테스트 수행 후 자료구조의 초기화를 수행하거나. @BeforeEach를 통해 테스트 마다 새로운 의존 객체를 주입해준다.

MemoryRepository의 Test코드.
AfterEach로 테스트 수행 후 repository의 map을 초기화 시킨다. 초기화하지 않으면 먼저 수행한 테스트의 결과와 뒤의 테스트에 영향을 끼쳐 독립성이 깨진다.
assetThat은 뒤의 결과가 만족하면 테스트를 성공적으로 수행시키며. 만족하지 않으면 테스트 실행시 에러를 발생시킨다.
테스트는 메서드별 또는 클래스별로 수행할 수 있다.

테스트 간에 독립성을 더 증강시킬 수 없을까?

현재는 의존 클래스 객체를 생성하고. 모든 테스트에 해당 객체를 사용한다.
즉 Service는 Repository 객체를 하나 생성. 하나의 Map 변수를 한 메서드의 테스트 쓰고 초기화하고 반복하며 사용한다.
테스트마다 BeforeEach로 새로운 Repository 객체를 생성하여 새로운 Map을 만들도록 하자.

Service 클래스를 변경하여 멤버 변수로 의존 클래스인 Repository 객체를 갖고.
Service 생성자에서 Repository 매개변수로 받도록 하였다.
1. Repository 객체를 수정하여 넣어주는 방식으로 해결되므로, 상위 클래스에서 의존클래스를 수정하지 않아도됨.
2. Repository 객체를 재생성 해서 넣어주는 방식으로, 완전 독립적인 단위테스트 가능

Service의 테스트. 의존 클래스 객체를 멤버 변수로 갖고. 모든 테스트 전에 이를 재생성하여 넣어줌으로서. 독립성 보장.


4. 의존 관계와 의존성 주입(DI)

의존 관계 : 한 클래스에서 타 클래스의 객체를 생성하여 사용하는 것.
ex) Service 클래스에서 로직 수행을 위해 리포지토리나 도메인 객체를 생성해 사용.

의존관계의 문제는 하위 클래스가 수정되면, 이를 의존하여(해당 클래스의 객체를 생성하여) 사용하는 모든 클래스도 함께 수정되어야 하는 것이다.

의존성 주입(DI) : 상위 클래스 멤버 변수로 의존 클래스 객체를 갖고 있기만 하고. 생성자로 의존 클래스 객체를 받아 멤버 변수를 갱신시켜 사용하는 것. 상위 클래스 생성자에 의존 클래스 객체를 넣어주는 방식을 가장 많이 사용한다.

public class MemberService {

    private final MemberRepository memberRepository; //멤버 변수로 의존 클래스를

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository; //생성자에서 이를 갱신
    }
}

예를 들어 레포지토리를 memoryMemberRepository에서 MysqlMemberRepository로 변경한다고 가정하자.
기존 방식은 MemberRepository 객체를 생성하는 모든 클래스에서 MemberRepository memberRepository = new MysqlMemberRepository()로 변경해야 할 것이다.
하지만 DI를 활용하면 의존 클래스만 변경하면, 상위 클래스에서 매개변수로 넣는 객체도 함께 변경되므로 상위클래스는 변경할 필요가 없다.


5. 스프링 빈과 의존관계

스프링 빈 : 스프링 컨테이너에 등록되어, 스프링이 관리하는 객체. 싱글톤 방식으로 객체는 하나씩만 생성되어 공유한다. 컴포넌트 스캔 방식 또는 직접 등록을 통해 스프링 빈으로 설정 가능하다.

의존 주입 : 스프링은 스프링 빈간에 의존 주입 기능을 제공한다. 직접 등록의 메서드 return에서 매개변수를 넣거나. 클래스의 생성자에서 @Autowired 어노테이션을 통해 의존주입이 가능하다.

1) 컴포넌트 스캔

스프링 빈으로 등록할 클래스 앞에 @Component. 또는 @Controller, @Service, @Repository 의 어노테이션을 추가한다.

생성자에서 @Autowired 어노테이션을 통해 스프링 빈 간에 의존 주입이 가능하다.

2) 직접 등록

SpringConfig 파일에 @Bean 어노테이션으로 추가한다.
return 에서 파라미터로 의존 클래스 생성 메서드를 넣어 의존 주입도 가능하다. 위의 예시는 memberService를 스프링 빈으로 등록하면서 memberRepository를 의존 주입한 모습이다.

좋은 웹페이지 즐겨찾기