AutoParams의 10.3.1 버전 릴리스에는 형 안정적으로 매개변수를 지정하는 set 메서드가 새롭게 추가됐다. 이 글은 기존 방식과 새롭게 추가된 set DSL의 차이점과 사용법을 설명한다.

기존 방식

AutoParams로 테스트 데이터를 생성할 때, 특정 매개변수나 속성에 원하는 값을 지정하는 방법은 여러 가지가 있다. 가장 기반이 되는 방법은 autoparams.customization.Customizer 인터페이스를 구현하는 것이고, autoparams.customization.dsl.ArgumentCustomizationDsl 클래스의 freezeArgument DSL 메서드를 사용할 수도 있다.

예를 들어, 아래와 같이 Product 레코드 클래스와 Review 레코드 클래스가 있다고 하자.

public record Product(
    UUID id,
    String name,
    String imageUri,
    String description,
    BigDecimal priceAmount,
    int stockQuantity
) {
}
public record Review(
    UUID id,
    UUID reviewerId,
    Product product,
    int rating,
    String comment
) {
}

AutoParams를 사용해서 Review 레코드 인스턴스를 생성할 때 productrating 값을 고정하려면 다음과 같이 매개변수 이름을 문자열로 지정할 수 있다.

import static autoparams.customization.dsl.ArgumentCustomizationDsl.freezeArgument;

public class TestClass {

    @Test
    @AutoParams
    void testMethod(Product product, @Max(5) int rating, ResolutionContext context) {
        context.customize(
            freezeArgument("product").to(product),
            freezeArgument("rating").to(rating)
        );
        Review review = context.resolve();
        assertSame(product, review.product());
        assertEquals(rating, review.rating());
    }
}

freezeArgument 메서드는 여러 오버로드를 갖고 다양한 조건을 사용해 매개변수를 지정할 수 있도록 설계되었다. 예를 들어 형식이 서로 달라도 이름이 같은 여러 매개변수에 null을 지정할 수 있다.

다만 이 방식은 유연하지만, 매개변수 이름이 바뀌면 문자열도 함께 수정해야 하므로 리팩터링에 취약하다. 또한, 오타가 발생해도 컴파일 타임에 잡아낼 수 없다는 단점이 있다.

set DSL 메서드

이런 불편함을 해소하기 위해 ArgumentCustomizationDsl 클래스에 set 메서드가 도입됐다. set 메서드는 문자열 대신 속성 접근자(getter 메서드나 레코드 클래스의 접근자)를 사용해 매개변수를 지정한다. 덕분에 리팩터링에 안전하고, 코드 편집기의 자동완성 기능도 활용할 수 있다.

아래 예시에서 set(Review::product)Review 레코드의 product 속성에 접근하는 메서드 참조를 사용한다.

import static autoparams.customization.dsl.ArgumentCustomizationDsl.set;

public class TestClass {

    @Test
    @AutoParams
    void testMethod(Product product, @Max(5) int rating, ResolutionContext context) {
        context.customize(
            set(Review::product).to(product),
            set(Review::rating).to(rating)
        );
        Review review = context.resolve();
        assertSame(product, review.product());
        assertEquals(rating, review.rating());
    }
}

이 방식의 장점은 다음과 같다:

  • 매개변수 이름을 문자열로 지정하는 대신, 타입 안전한 메서드 참조를 사용한다.

  • 매개변수 이름이 바뀌더라도 리팩터링 기능으로 안전하게 코드를 변경할 수 있다.

  • 오타나 잘못된 지정은 컴파일 타임에 바로 확인할 수 있다.

비슷하게 set DSL은 ResolutionContext뿐 아니라 Factory<T>와도 함께 사용할 수 있다.

import static autoparams.customization.dsl.ArgumentCustomizationDsl.set;

public class TestClass {

    @Test
    @AutoParams
    void testMethod(Product product, @Max(5) int rating, Factory<Review> factory) {
        Review review = factory.get(
            set(Review::product).to(product),
            set(Review::rating).to(rating)
        );
        assertSame(product, review.product());
        assertEquals(rating, review.rating());
    }
}

이렇게 set DSL을 사용하면 문자열로 매개변수 이름을 직접 지정하지 않고, 타입 안전한 메서드 참조로 매개변수를 지정할 수 있다. 이로써 테스트 데이터 생성 코드를 더 명확하고 직관적으로 작성할 수 있으며, 리팩터링이나 유지보수도 한층 수월해진다. 상황에 따라 freezeArgumentset 메서드를 적절히 선택해 사용할 수 있다.

set 메서드는 매개변수 이름에 의존합니다. 매개변수 이름에 대해서는 이 글을 참고하세요.