slipp / jwp-book

자바 웹 프로그래밍 학습을 위한 저장소
381 stars 131 forks source link

테스트 클래스 안의 멤버변수의 생존주기 (52페이지 내용 ) #1

Closed benelog closed 7 years ago

benelog commented 7 years ago

52페이지에 아래와 같은 내용이 있습니다.

@Before 애노테이션을 사용하지 않고 필드로 구현하는 방법은 CalculatorTest의 인스턴스가 생성될 때 Calculator 인스턴스가 생성되어 모든 테스트 메서드가 재활용하는 방식으로 동작한다. 이와 같이 Calculator 인스턴스가 재사용될 경우 ...

그런데 아래와 같은 테스트를 돌려보면 멤버변수인 list는 재활용되지 않음을 확인할수 있습니다.

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class GoTest {

    List<String> list = new ArrayList();

    @Test
    public void go1() {
        list.add("go1");
        System.out.println(list);
    }

    @Test
    public void go2(){
        list.add("go2");
        System.out.println(list);

    }

    @Test
    public void go3(){
        list.add("go3");
        System.out.println(list);

    }
}
javajigi commented 7 years ago

테스트해본 결과 내가 잘못 알고 있었네. 직접 확인하지 않고 @Before의 필요성을 고민하면서 내 추측으로 판단해 버렸네.

다음 버전에 수정해서 반영할께. 고맙다.

그렇다면 @Before가 필요성은 클래스들간의 의존 관계를 가지면서 초기화를 하는 경우 정도로 생각해야 할까?

benelog commented 7 years ago

@Before는 JUnit의 Runner와 Rule에 의한 초기화가 끝난 후에 공통 테스트 환경(대상객체/Fixture)를 세팅할 기회를 주는 의미가 있을것 같네요.

단순한 의존관계 초기화라면 생성자 안에서해도 같은 효과가 있기는합니다. 아래와 같이 해봐도 모든 테스트 메서드 전에 생성자 블럭안의 코드가 실행됩니다.

    public GoTest()  {
        System.out.println(111);
    }

그런데 @Rule, @RunWith 같은 것과을 쓰면 꼭 @Before 안이어야만 Runner 등에 의해 초기화된 객체에 접근할수 있습니다. 예를 들면 아래 코드처럼 생서자 안에서 TemporaryFolder 객체에 접근을 하니 에러가 나더라구요. (commenting out한 부분)

    @Rule
    public TemporaryFolder folder= new TemporaryFolder();

    public GoTest() throws IOException {
        // System.out.println(folder.newFile().getAbsolutePath());
    }

    @Before
    public void setUp() throws IOException {
        System.out.println(folder.newFile().getAbsolutePath());
    }

사실 저도 깊이 생각은 안 해보고 그냥 습관적으로 쓰고 있었는데, 좋은 질문을 주셨네요 ^^;

javajigi commented 7 years ago

이 부분은 생각도 못했네. 덕분에 나도 하나 배우고 간다.

책에 이 내용을 모두 포함할 수는 없으니 다른 방식으로 풀어봐야겠다. 고맙다.

WoongE commented 6 years ago

자바지기님 안녕하세요. ㅎㅎ 책을 재미있게 읽고 있는 독자입니다. 저도 책을 읽다보니 이 부분에서 오류를 발견해서, 혹시 온라인에 관련 내용이 있을까 하여 들어와봤는데 역시나 있네요. ㅎㅎ

테스트 객체 안에 private Calculator cal = new Calculator(); 방식으로 선언을 해도 매 테스트마다 Calculator 인스턴스가 새로 생성되는 이유는, 매 @Test 매서드가 실행될 때마다 CalculatorTest 클래스의 인스턴스가 아예 새로 생성되기 때문이라고 알고 있습니다.

이렇게 구현되어 있는 이유는 JUNIT이 각 테스트 매서드들의 독립성을 보장하기 위해서라고 합니다.

<토비의 스프링 3.0> 2장의 2.3.5절을 보면 나와있습니다. image (제가 제 개인 블로그에 정리했던 자료입니다. https://blog.naver.com/woong17/221114148233)

책 정말 정말 유익하게 보고 있습니다. ㅎㅎ 감사합니다. 앞으로도 좋은 책 많이 써주세요! ㅎㅎ

javajigi commented 6 years ago

@Woonge 피드백 감사합니다. 조만간 2쇄를 찍을 때 수정해서 배포하도록 하겠습니다.

제 책이 @Woonge 님이 성장하는데 도움이 되기를 바랍니다.

benelog commented 6 years ago

2판을 낸다면 JUnit5를 기반으로 해도 좋을거 같습니다. @BeforeEach 처럼 애노테이션의 이름들이 더 명확해진 느낌입니다.