스터디 날짜
24.07.15.
스터디 범위
2장. 테스트
💬 스프링이 개발자에게 제공하는 가장 중요한 가치가 무엇이냐고 질문한다면 나는 주저하지 않고 객체지향과 테스트라고 대답할 것이다.
테스트는 가능하면 작은 단위로 쪼개서 집중해서 할 수 있어야 한다. 관심사의 분리가 여기에도 적용된다.
단위 테스트가 필요한 이유
💬 켄트 벡, “테스트란 개발자가 마음 편하게 잠자리에 들 수 있게 해주는 것”
메소드가 public으로 선언되어야 한다.
메소드에 @Test라는 어노테이션을 붙인다.
(+리턴값이 void형이고 파라미터가 없어야 한다.)
if (!user.getName().equals(user2.getName())) { ... }
assertThat(user2.getName(), is(user.getName()));
matcher
의 일종으로, equals()로 비교해주는 기능을 가진다.JUnit은 특정한 테스트 메소드의 실행 순서를 보장해주지 않는다.
모든 테스트는 실행 순서에 상관없이 독립적으로 항상 동일한 결과를 낼 수 있도록 해야 한다.
assertThat()
메소드로는 검증이 불가능하다.// 테스트 중에 발생할 것으로 기대하는 예외 클래스를 지정해준다.
@Test(expected=EmptyResultDataAccessException.class)
💬 로드 존슨, “항상 네거티브 테스트를 먼저 만들라”
💬 만들고자 하는 기능의 내용을 담고 있으면서 만들어진 코드를 검증도 해줄 수 있도록 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발
→ (정원용 멘토님) 개발 초반에 TDD를 하게 되면 코드를 변경하거나 리팩터링 해야할때 테스트코드가 망가진다는 생각에 코드 수정을 망설이게 될 수 있다…
@Test
가 붙은 public이고 void형이며 파라미터가 없는 테스트 메소드를 모두 찾는다. 💁 각 테스트가 서로 영향을 주지 않고 독립적으로 실행됨을 확실히 보장해주기 위해서 매번 새로운 오브젝트를 만든다.
@Before
가 붙은 메소드가 있으면 실행한다. @Test
가 붙은 메소드를 하나 호출하고 테스트 결과를 저장해둔다. @After
가 붙은 메소드가 있으면 실행한다. 💬 테스트를 수행하는 데 필요한 정보나 오브젝트를 말한다. 일반적으로 픽스처는 여러 테스트에서 반복적으로 사용되므로
@Before
메소드를 이용해 생성해두면 편리하다.
테스트 클래스 전체에 걸쳐 딱 한번만 실행된다.
여러 테스트가 함께 참조할 애플리케이션 컨텍스트를 오브젝트 레벨에 저장해두면 곤란하므로, 스태틱 필드에 애플리케이션 컨텍스트를 저장해두는 방식을 고민해볼 수 있다.
하지만 스프링이 직접 제공하는 애플리케이션 컨텍스트 테스트 지원 기능을 사용하는게 더 편리하다!
@AutoWired
어노테이션을 붙인다.@RunWith
어노테이션을 붙여 JUnit 확장기능을 지정한다.@ContextConfiguration
어노테이션을 붙여 테스트 컨텍스트가 자동으로 만들어줄 애플리케이션 컨텍스트의 위치를 지정한다. → 같은 설정파일을 가진 애플리케이션 컨텍스트를 사용하면, 테스트 클래스 사이에서도 애플리케이션 컨텍스트를 공유할 수 있다. (성능 대폭 향상)변수 타입
과 일치하는 컨텍스트 내의 빈을 찾고, 타입이 일치하는 빈이 있으면 인스턴스 변수에 주입해준다. 이때 생성자나 수정자 메소드가 없어도 주입이 가능하다.변수 이름
과 같은 이름의 빈이 주입된다.예외
가 발생한다.❓ 구현 클래스를 절대 바꾸지 않을 경우에도 굳이 인터페이스를 사용하고 DI를 통해 주입해주는 방식을 이용해야 하는가? → 🙆♀️
@DirtiesContext -> 테스트 메소드에서 애플리케이션 컨텍스트의 구성이나 상태를 변경
public class UserDatTest {
@Autowired
UserDao dao;
@Before
public void setUp() {
DataSource dataSource = new SingleConnectionDataSource(
"jdbc:mysql://localhost/testdb", "spring", "book", true);
dao.setDataSource(dataSource); // -> 코드에 의한 수동 DI
}
이 어노테이션이 붙은 클래스에는 애플리케이션 컨텍스트 공유를 허용하지 않으므로, 테스트 중에 변경한 컨텍스트가 뒤의 테스트에 영향을 주지 않는다.
이 어노테이션이 붙어있는 클래스나 메서드에서 애플리케이션 컨텍스트를 새로 만들고, 실행이 끝나고 나면 해당 컨텍스트는 폐기하고 다시 새로운 애플리케이션 컨텍스트가 만들어진다.
→ 아무래도 찜찜하므로, 그냥 테스트용 설정 파일을 따로 만드는게 낫다! 번거롭게 수동 DI 하거나 위의 어노테이션을 달아줄 필요가 없어짐 👍
💬 자신이 만들지 않은 프레임워크나 다른 개발팀에서 만들어서 제공한 라이브러리에 대해 작성하는 테스트를 학습테스트라고 한다. 테스트이지만 기능 검증이 목적이 아니며, 기술이나 기능을 자신이 얼마나 제대로 이해하고 있는지를 검증하는 것이 목적이다.
스프링 배포판의 압축을 풀어보면 프레임워크 소스코드와 함께 테스트 코드를 살펴볼 수 있다 → 좋은 공부자료
either
(is(nullValue())).or
(is(this.context))));💬 버그 테스트란 코드에 오류가 있을 때 그 오류를 가장 잘 드러내줄 수 있는 테스트를 말한다. 버그 테스트는 일단 실패하도록 만들고, 이후에 버그 테스트가 성공할 수 있도록 애플리케이션 코드를 수정한다.