Spring/Test-Driven Develop

[Junit] Test Fixture 란 ❓

민돌v 2022. 10. 28. 12:26
  • Test Fixture 의 이해를 위한 글입니다.
  • Test Fixtures 개념을 실제로 사용하는 2가지 방법을 다룹니다.
  • 코드는 ⚙️ Github 에 있습니당!!

 

 

 

Test Fixture 란

일종의 개념이라고 생각합니다. 중복 발생되는 무언가(행위)를 고정시켜 한곳에 관리하도록 하겠다는 개념.

 


 

Test Fixture 를 사용 예시 

금액과 나라를 가지고있는 Money 객체가 있다고 해봅니다.

@Getter
@AllArgsConstructor
@EqualsAndHashCode
public class Money {

    private int money;
    private String country;

    /** 돈 더하기 **/
    public Money add(Money anotherMoney) {
        checkOrigin(anotherMoney.getCountry());
        money+= anotherMoney.getMoney();

        return new Money(money, country);
    }
    
    /** 나라 비교하기 **/
    private void checkOrigin(final String country) {
        if (!country.equals(country)) {
            throw new NullPointerException("같은 나라 돈이 아니에여!");
        }
    }
}

 

이제 Money 객체를 테스트합니다

@Test
public void simpleAdd() {
    Money m12CHF= new Money(12, "CHF");
    Money m14CHF= new Money(14, "CHF");
    Money expected= new Money(26, "CHF");
    Money result= m12CHF.add(m14CHF);

    Assertions.assertThat(expected).isEqualTo(result);
}

 

이와 같은 상황에서, 다른 테스트를 진행한다고할 때, 아래처럼 똑같은 Money 객체를 매번 생성해야하는 상황이 생기겠죠??

@Test
public void simpleAdd() {
    Money m12CHF= new Money(12, "CHF");
    Money m14CHF= new Money(14, "CHF");
    Money expected= new Money(26, "CHF");
    Money result= m12CHF.add(m14CHF);

    Assertions.assertThat(expected).isEqualTo(result);
}

//예시를 위해 위와 같은 테스트지만,, 그냥 중복 발생된 다른 테스트 예제라고 생각해주세요ㅎㅎ
@Test
public void anotherAdd() {
    Money m12CHF= new Money(12, "CHF");
    Money m14CHF= new Money(14, "CHF");
    Money 다른비교객체= new Money(26, "CHF");
    Money 다른테스트결과= m12CHF.add(m14CHF);

    Assertions.assertThat(다른비교객체).isEqualTo(다른테스트결과);
}

 

Junit 에서는 이러한 상황, 즉 "동일하거나 유사한 개체 집합에 대해 작동하는 두 개 이상의 테스트가 있는경우" 테스트 픽스쳐를 사용하라고 권유합니다.

 


🙌🏻 Test Fixture 메소드 사용

위와같은 상황에서는 중복된 객체를 사전에 미리 정의해서 고정해두는 방식으로 픽스쳐를 구성할 수 있습니다.

private Money f12CHF_fixture;
private Money f14CHF_fixture;
private Money f28USD_fixture;

@BeforeAll
public void setUp() {
    f12CHF_fixture= new Money(12, "CHF");
    f14CHF_fixture= new Money(14, "CHF");
    f28USD_fixture= new Money(28, "USD");
}

 

junit 에서는 이러한 기능의 픽스쳐 메소드를 제공합니다.

Annotation Description
@BeforeAll 테스트 메소드 시작 전 1번 실행
@AfterAll 테스트 메서드 종료 후 1번 실행
@BeforeEach 각 테스트 메소드 시작 전 실행
@AfterEach 각 테스트 메소드 종료 후 실행

 

 

개념이기 때문에 Fixture를 구성하는 방법은 다양하다고 생각합니다.

junit4 공식문서에서 말하는 fixture 는 테스트 픽스처 메소드를 사용하라고 합니다.

 


 

👏🏻 Test Fixtures 를 구성하는 다른 방법

이 개념을 토대로 코틀린에서 Fixture 라는 파일에  많은 생성자 케이스를 만들어 별도로 테스트에서 사용하는 객체의 생성을 관리하는 픽스쳐를 사용하는 우아한 테크 코스 깃허브 레포지토리입니다.

https://github.com/woowacourse/service-apply/blob/master/src/test/kotlin/apply/JudgmentFixtures.kt

 

 

우아한 테크코스 레포지토리 경우 테스트 픽스쳐를, 객체의 생성자를 이용해서 객체가 생성될 경우를 미리 정의해두어서 세팅에 관련된 부분은 한 곳에서만 관리하고, 테스트에서는 가져다 쓰겠다,,!! 

라는 의도가 담겨있다고 느껴졌습니다.

 

해당 예시의 코틀린 코드를 자바 코드로 변경하면 이런식으로 Test Fixtrues 를 구성해볼 수 있을거같습니다.

Fixtures

public class MoneyFixtures {
    public static Money createMoney(final int money) {
        return new Money(money, "default");
    }

    public static Money createMoney(final String country) {
        return new Money(10000, country);
    }

    public static Money createMoney(final int money, final String country) {
        return new Money(money, country);
    }
}

Test

public class MoneyFixtureTest {
    private Money m12CHF = MoneyFixtures.createMoney(12);
    private Money m14CHF = MoneyFixtures.createMoney(14);

    @Test
    public void simpleAdd() {
        Money expected = MoneyFixtures.createMoney(26);
        Money result= m12CHF.add(m14CHF);

        Assertions.assertThat(expected).isEqualTo(result);
    }
}

 

 

테스트 픽스쳐는 개념일뿐 위의 2가지 방법이 정답인것은 아닙니다!

실제로 자바지기 박재성님께서는 2번째 방법인 별도의 Fixture를 관리하는 방법은 사용하지않고 그때마다 생성자를 만든다고 들었습니다.

 

📌 모든 선택은 유지보수가 편한 방법으로!!!

 

 


*참고