토비의 스프링 2장 정리

메이도·2023년 3월 11일

1장의 UserDaoTest의 메인으로 작성한 테스트는 매번 직접 db의 정보를 삭제하고, 직접 결과를 비교하며 테스트를 진행해야 하는 단점이 있다

테스트의 조건

  • 테스트의 결과가 어떤 조건에서도 일정할 것
  • 테스트는 자동으로 진행될 것
  • 테스트 결과는 사용자가 눈으로 비교하지 않아도 되게 자동으로 비교해줄 것
  • 한 번에 다양한 기능을 테스트 할 수 있도록 진행

2.1

작은 단위 테스트

  • 작은 단위 테스트: 테스트는 한 번에 많은 것을 테스트 하면 테스트가 복잡해지고 오류 시 정확한 원인을 찾을 수 없어서 작은 단위로 쪼개서 수행해야 한다(관심사의 분리: 테스트의 관심이 다르다면 테스트할 대상을 분리하고 집중해서 접근해야 한다)
  • 단위테스트: 작은 단위의 코드에 대해 테스트를 수행한 것
    • 테스트 중 db가 사용되면 단위 테스트가 아니다? ⇒ 사용할 db의 상태를 테스트가 관장하고 있다면 단위테스트다.(db 상태가 매번 달라짐 x, db 특정 상태로 만들어주기 가능)
    • 단위 테스트의 장점: 개발자가 설계하고 만든 코드가 원래 의도대로 동작하는지 개발자가 확인하기 위해서(개발자 테스트/프로그래머 테스트)→ 버그를 빠르게 수정할 수 있음

자동 수행 테스트

  • 테스트는 자동으로 수행되어야 여러 번 자주 할 수 있다.→ 하나의 수정/추가로 다른 기능에 영향을 끼치지 않는지 빠르게 확인할 수 있다.
  • 기존 테스트는 add() 수행 후 get()을 출력해 결과를 보여주지만 입력값과 출력값이 일치하는지는 사람이 비교해야 함(수고로움/실수 가능성)

2.2

2.2.1 테스트 검증의 자동화

테스트 실패

  1. 테스트 진행 중 에러 발생(테스트 에러)
  2. 테스트의 결과값이 기대와 다름(테스트 실패)-> 통과 못함

2.2.2 테스트의 효율적인 수행과 결과 관리(Junit)

프레임워크의 동작 원리는 IoC이기에 프레임워크에서 동작하는 코드는 main()메소드나 오브젝트 실행 코드도 필요 없다.→ main()의 테스트 코드를 일반 메소드로 옮기기

  1. 메소드가 public으로 선언
  2. @Test 어노테이션

java.lang.Exception: No runnable methods(main에서 실행할 때만)

import org.junit.Test;(후) ⇒ main 메서드에서 테스트 실행 가능

import org.junit.jupiter.api.Test;(전) ⇒ 함수 단위로 테스트 실행 가능

assertThat(T actual, Matcher<? super T> matcher)

의 형태로 matcher로 is를 사용해 첫 번째 파라미터와 is 자신의 파라미터가 동일한지 비교하고 테스트 오류시 AssertionError 생성

2.3

db를 삭제하고 테스트를 실행하지 않으면 테스트 오류가 발생하는데 동일한 코드로 반복적으로 테스트 수행 시 테스트의 성공 여부가 달라지면 안된다

테스트 수행 후 사용자 정보를 삭제하자(모종의 이유로 테스트 시작 전 users 테이블에 데이터가 들어가 있을 수 있음.

테스트 전 users 테이블을 비우고 테스트 시작(이 방법 채택)

addAndGet() 테스트 보완

보완해라~

dao.get(user1.getId());가 없을 때→ 테스트 에러

1) null 리턴

2) id 해당 정보를 찾을 수 없다고 예외 던지기→ 에러 코드가 테스트를 통과하도록 설정!

@Test 어노테이션이 붙은 테스트 별로 통과됐음을 확인할 수 있다

포괄적 테스트를 만들자: 간단해보여도 다양한 상황과 입력값을 고려하는 테스트할 수 있는 포괄적인 테스트코드를 만들어둬야 특정한 상황에서의 오동작 확인 가능 + 네거티브 테스트(를 만들자!)

2.3.4 테스트 실패 코드 생성→ 코드 수정(테스트가 이끄는 개발: TDD)

테스트의 조건, 행위, 결과를 사전에 문서의 형식으로 생성 후 코드를 생성하자

조건: 사용자 정보 존재 X/ 행위: 없는 id로 get/결과: 예외 던짐

⇒ 테스트코드를 설계 문서처럼 표현 가능

TDD: 만들고자 하는 기능을 담은 테스트 코드 생성→ 테스트 성공을 위한 코드 작성하는 방식

실패한 테스트를 성공시키기 위한 목적이 아닌 코드는 만들지 않는다!

TDD의 장점

  • 테스트를 작은 단위부터 꼼꼼하게 실행 가능
  • 코드 작성 후 바로 테스트 실행으로 테스트와 코드 작성 간의 시간 간격이 짧아짐→ 코드 피드백 빠름(오류 발견 빠름)
  • 코드 확신, 자신감, 여유!
  • 단위테스트 생성 가능

테스트 작성의 작업 주기는 짧게!(테스트 조금 작성, 바로 코드 작성) 이 단계를 자주 반복할 것

JUnit 작동 방식

public void 형 @Test 메소드 검색→ 테스트 메소드마다 클래스 오브젝트 생성→ @Before 실행→ 테스트 메소드 실행 후 결과 저장→ @After 실행→ 모든 테스트 완료 후 결과 반환

테스트 메소드마다 새로운 클래스 생성 → 각 테스트가 독립적으로 실행됨을 보장하기 위해

픽스처: 테스트 수행에 필요한 정보나 오브젝트

2.4

@Before 메소드마다 애플리케이션 컨텍스트가 세 번 만들어진다.→ 빈의 초기화와 생성에 리소스가 많이 사용된다

@Autowired: DI용 어노테이션으로 Autowired가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내 빈 검색 후 타입과 일치하는 빈 있으면 인스턴스 변수에 주입. & DI 설정 없이 필드의 타입 정보로 빈 가져오기 가능(타입에 의한 자동 와이어링)

@RunWith(SpringJunit4ClassRunner.class)(스프링 테스트 컨텍스트 프레임워크의 Junit 확장 기능 사용할거라 지정함): 어플리케이션 컨텍스트와는 다른 스프링 테스트 컨텍스트!!

@ContextConfiguration(테스트 컨텍스트 자동 생성될 애플리케이션 컨텍스트 위치 지정): 빈 정보 지정 위치 명시로 이 파일에서 빈을 검색해서 주입해준다.

Junit 확장 기능은 테스트 실행 전 한 번 AC 만들고, 테스트 오브젝트 생성 때 마다 컨텍스트를 주입하는데 스프링 AC는 초기화 시 자기 자신도 빈으로 등록함.

스프링 테스트 컨텍스트 프레임워크

  • 하나의 테스트 클래스 안에서 @Test마다 AC를 공유해줌
  • 여러 개의 테스트 클래스들 사이에서도 AC를 공유해줌→ 테스트 성능 대폭 향상

Autowired는 타입을 가진 빈을 자동으로 찾는데 같은 타입의 빈이 두 개 이상 있으면 어떤 빈을 가져올지 정하지 못한다.→ 이럴 경우 변수의 이름과 같은 이름의 빈이 있는지 확인


빈을 등록한다는 것: 어떤 함수가 어떤 객체를 생성해서 반환하는지, 어떤 객체를 주입하는지 그 관계를 적어놓는다는 것

  • bean id: 빈의 이름
  • class: 빈이 생성하는 객체
  • property: 빈이 생성하는 객체에서 사용하는 속성
  • value: property에서 사용하는 값
  • name: setter의 프로퍼티(주입되는 매개변수)
  • ref: 주입할 빈 ID

⇒ UserDao Setter 함수의 매개변수 이름인 dataSource에 빈 dataSource의 값(SimpleDriverDataSource)를 넣는다!

빈 등록→ 객체간의 관계에 대한 정보 등록(사전 같은 것)

UserDao라는 타입을 가진 빈을 검색→ id가 userDao인 빈

⇒ @Autowired 설정만 하면 알아서 AC 참고해서 db 연결까지 해준다!

this.dao = this.context.getBean("userDao", UserDao.class);

이러한 DL 작업을 대신 해주는 것이 스프링 컨테이너이다 = 이런 작업을 코드 내에서 DaoFactory 해주고 있는데 이러한 IoC 작업을 해주는 것이 스프링 컨테이너 = DaoFactory가 없어도 빈만 등록됐으면 된다

XML파일 작성 후 @Autowired <=> (대체) @Bean 어노테이션으로 빈 등록, getBean으로 빈 검색해서 가져오는 단계

결론: 스프링 IoC= FactoryClass(우리가 쓰는 스프링부트 방식)

기존에는 의존성 주입 =new를 하지 않아도 객체 생성 이라고 생각을 했었는데
객체 생성에 필요한 프로퍼티를 스프링 컨테이너가 자동으로 주입해주는 IoC를 수행하는 것

0개의 댓글