요금제

프로젝트 개요

관련 소스 파일

이 페이지의 내용은 다음 소스 파일을 기반으로 생성되었습니다:

Fixture Monkey는 Java와 Kotlin 환경에서 테스트 객체를 자동으로 생성하고 제어할 수 있도록 설계된 오픈소스 라이브러리다. "Write once, Test anywhere"라는 슬로건 아래, 복잡한 테스트 픽스처 생성 과정을 단순화하고 테스트 코드의 유지보수성을 높이는 것을 핵심 목표로 한다 (README.md:1-28).

이 라이브러리의 가장 독특한 특징은 경로 기반 표현식을 통해 중첩된 필드에 자유롭게 접근하고 설정할 수 있다는 점이다. 개발자는 복잡한 객체 그래프를 수동으로 구성할 필요 없이, 단일 표현식으로 깊이 중첩된 속성까지 제어할 수 있다 (docs/docs/introduction/overview.mdx:1-29).

Naver에서 개발된 Fixture Monkey는 실제 운영 환경에서 검증된 신뢰성을 갖추고 있다. 한국의 대표적인 모바일 결제 서비스에서 10,000개 이상의 테스트를 지원하며 복잡한 비즈니스 요구사항을 처리하는 데 성공적으로 활용되고 있다 (README.md:191-220).

기술 스택 및 요구사항

구분항목버전/설명
언어Java (JDK)1.8 이상
Kotlin1.8 이상 (Kotlin 지원 시)
프레임워크Jqwik1.7.3
Kotest Property5.9.1 (Kotlin 지원 시)
라이선스Apache 2.0오픈소스
빌드 도구Gradle / Maven둘 다 지원
IDE 지원IntelliJ IDEAFixtureMonkey Helper 플러그인

(README.md:191-220)

프로젝트 디렉토리 구조

fixture-monkey/
├── fixture-monkey/                    # 핵심 라이브러리 모듈
│   └── src/main/java/com/navercorp/fixturemonkey/
│       ├── FixtureMonkey.java         # 주요 진입점 클래스
│       ├── FixtureMonkeyBuilder.java  # 빌더 패턴 구현
│       ├── ArbitraryBuilder.java      # 객체 생성 인터페이스
│       ├── ArbitraryBuilders.java     # 유틸리티 클래스
│       └── Constants.java             # 상수 정의
├── docs/                              # 문서화
│   └── docs/introduction/
│       └── overview.mdx               # 개요 문서
├── fixture-monkey-benchmarks/         # 성능 벤치마크
│   └── fixture-monkey-benchmark/
│       └── src/jmh/java/com/navercorp/fixturemonkey/
├── README.md                          # 프로젝트 소개
└── LICENSE                            # Apache 2.0 라이선스

핵심 기능 및 특징

원라인 테스트 객체 생성

전통적인 테스트 객체 생성 방식에서는 수많은 setter 호출과 보일러플레이트 코드가 필요했다. Fixture Monkey는 이를 단일 라인으로 대체한다.

java
1// Before: 수동 객체 생성
2Product product = new Product();
3product.setId(1L);
4product.setName("Test Product");
5// ... 많은 setter 호출
6
7// After: Fixture Monkey 사용
8Product product = fixtureMonkey.giveMeOne(Product.class);

(README.md:119-171)

직관적인 경로 기반 설정

경로 표현식을 통해 중첩된 필드에 직접 접근할 수 있다. items[*].product.name과 같은 표현식으로 리스트 내 모든 항목의 중첩 속성을 한 번에 설정할 수 있다.

java
1ArbitraryBuilder<Order> orderBuilder = fixtureMonkey.giveMeBuilder(Order.class)
2    .set("items[*].product.name", "Special Product");

(README.md:119-171)

재사용 가능한 테스트 스펙

한 번 정의된 ArbitraryBuilder는 여러 테스트에서 재사용할 수 있다. 이를 통해 테스트 코드 중복을 제거하고 일관된 테스트 데이터를 유지할 수 있다.

java
1ArbitraryBuilder<Product> productBuilder = fixtureMonkey.giveMeBuilder(Product.class)
2    .set("category", "Book")
3    .set("price", 1000);
4
5Product product1 = productBuilder.sample();
6Product product2 = productBuilder.size("reviews", 3).sample();

(README.md:119-171)

범용 객체 생성

상속, 순환 참조, 복잡한 구조를 포함한 모든 종류의 객체 구조를 처리할 수 있다. 단순한 POJO부터 복잡한 객체 그래프까지 자동으로 생성한다.

java
1Foo foo = FixtureMonkey.create().giveMeOne(Foo.class);  // 순환 참조 포함
2Bar bar = FixtureMonkey.create().giveMeOne(Bar.class);  // 상속 포함

(README.md:119-171)

동적 테스트 데이터

sample() 호출은 고유한 테스트 데이터를 생성한다. 정적인 테스트 데이터로는 발견하기 어려운 엣지 케이스를 찾을 수 있다.

java
1Product sample1 = fixtureMonkey.giveMeBuilder(Product.class).sample();
2Product sample2 = fixtureMonkey.giveMeBuilder(Product.class).sample();
3assertThat(sample1).isNotEqualTo(sample2);

(README.md:119-171)

ArbitraryBuilder 인터페이스

ArbitraryBuilder는 Fixture Monkey의 핵심 인터페이스로, 테스트 객체 생성을 위한 다양한 메서드를 제공한다. set 메서드는 경로 표현식과 값을 받아 해당 속성을 설정한다.

java
1ArbitraryBuilder&lt;T&gt; set(String expression, @Nullable Object value);
2ArbitraryBuilder&lt;T&gt; set(String expression, @Nullable Object value, int limit);
3ArbitraryBuilder&lt;T&gt; set(PropertySelector propertySelector, @Nullable Object value);

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/ArbitraryBuilder.java:53-92)

아키텍처 및 주요 컴포넌트

시스템 아키텍처

正在加载图表渲染器...

아키텍처 설명:

  1. 사용자 코드 레이어: 테스트 코드에서 FixtureMonkey.create() 또는 FixtureMonkey.builder()를 통해 인스턴스를 생성한다.
  2. API 레이어: giveMeBuilder(), sample() 등의 메서드를 통해 객체 생성을 요청한다.
  3. 핵심 엔진: FixtureMonkey, ArbitraryBuilder 등이 실제 객체 생성 로직을 처리한다.
  4. 설정 및 상수: FixtureMonkeyOptionsConstants가 기본 동작을 정의한다.
  5. 플러그인 생태계: Kotlin 지원, IntelliJ 플러그인 등 확장 기능을 제공한다.

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:62-133, fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java:75-134)

FixtureMonkey 핵심 클래스

FixtureMonkey는 라이브러리의 주요 진입점 클래스로, 다음과 같은 핵심 컴포넌트를 포함한다:

  • fixtureMonkeyOptions: 객체 생성 동작을 제어하는 옵션들
  • manipulatorOptimizer: 조작자 최적화기
  • monkeyContext: 컨텍스트 정보 관리
  • monkeyManipulatorFactory: 조작자 팩토리
  • monkeyExpressionFactory: 표현식 팩토리

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:62-133)

FixtureMonkeyBuilder 빌더 패턴

FixtureMonkeyBuilder는 빌더 패턴을 구현하여 FixtureMonkey 인스턴스를 유연하게 구성할 수 있게 한다. 주요 설정 가능 항목:

  • PropertyGenerator: 속성 생성기 등록
  • ObjectPropertyGenerator: 객체 속성 생성기 설정
  • ManipulatorOptimizer: 조작자 최적화기 지정
  • MonkeyExpressionFactory: 표현식 팩토리 구성
java
1FixtureMonkey sut = FixtureMonkey.builder()
2    .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
3    .build();

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java:75-134)

Constants 상수 정의

Constants 클래스는 라이브러리 전반에서 사용되는 기본값들을 정의한다:

상수명설명
DEFAULT_ELEMENT_MIN_SIZE0컬렉션 최소 크기
DEFAULT_ELEMENT_MAX_SIZE3컬렉션 최대 크기
NO_OR_ALL_INDEX_INTEGER_VALUEInteger.MAX_VALUE인덱스 없음/전체 표시
MAX_MANIPULATION_COUNTInteger.MAX_VALUE최대 조작 횟수
ALL_INDEX_STRING"*"모든 인덱스 표현
HEAD_NAME"$"헤드 이름

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/Constants.java:20-28)

객체 생성 호출 흐름

正在加载图表渲染器...

호출 흐름 설명:

  1. 빌더 생성: FixtureMonkey.builder()를 통해 빌더 인스턴스를 생성한다.
  2. 옵션 설정: objectIntrospector() 등의 메서드로 동작을 커스터마이징한다.
  3. 인스턴스 생성: build()를 호출해 FixtureMonkey 인스턴스를 생성한다.
  4. ArbitraryBuilder 획득: giveMeBuilder()로 특정 타입의 빌더를 얻는다.
  5. 조작 설정: set() 등의 메서드로 속성 값을 지정한다.
  6. 객체 생성: sample()을 호출해 최종 객체를 생성한다.

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkey.java:62-133, fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java:75-134)

사용 예시 및 시작하기

의존성 추가

Gradle (Java):

groovy
1testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter:1.1.18")

Gradle (Kotlin):

groovy
1testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter-kotlin:1.1.18")

Maven (Java):

xml
1<dependency>
2    <groupId>com.navercorp.fixturemonkey</groupId>
3    <artifactId>fixture-monkey-starter</artifactId>
4    <version>1.1.18</version>
5    <scope>test</scope>
6</dependency>

(README.md:29-95)

기본 사용법

Java 예시:

java
1// 가장 간단한 사용법
2FixtureMonkey fixtureMonkey = FixtureMonkey.create();
3Product product = fixtureMonkey.giveMeOne(Product.class);
4
5// 빌더 패턴을 통한 커스터마이징
6@Test
7void sampleOrder() {
8    FixtureMonkey sut = FixtureMonkey.builder()
9            .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
10            .build();
11
12    Order actual = sut.giveMeBuilder(Order.class)
13            .set(javaGetter(Order::getOrderNo), "1")
14            .set(javaGetter(Order::getProductName), "Line Sally")
15            .minSize(javaGetter(Order::getItems), 1)
16            .sample();
17
18    then(actual.getOrderNo()).isEqualTo("1");
19    then(actual.getProductName()).isEqualTo("Line Sally");
20    then(actual.getItems()).hasSizeGreaterThanOrEqualTo(1);
21}

(README.md:29-95)

Kotlin 예시:

kotlin
1@Test
2fun sampleOrder() {
3    val sut = FixtureMonkey.builder()
4            .plugin(KotlinPlugin())
5            .build()
6
7    val actual = sut.giveMeBuilder<Order>()
8            .setExp(Order::orderNo, "1")
9            .setExp(Order::productName, "Line Sally")
10            .minSizeExp(Order::items, 1)
11            .sample()
12
13    then(actual.orderNo).isEqualTo("1")
14    then(actual.productName).isEqualTo("Line Sally")
15    then(actual.items).hasSizeGreaterThanOrEqualTo(1)
16}

(README.md:29-95)

실제 테스트 시나리오

java
1@Test
2void testOrderProcessing() {
3    // Given
4    Order order = fixtureMonkey.giveMeBuilder(Order.class)
5        .set("items[*].quantity", 2)
6        .set("items[*].product.price", 1000)
7        .sample();
8    
9    // When
10    OrderResult result = new OrderProcessor().process(order);
11    
12    // Then
13    assertThat(result.getTotalAmount()).isEqualTo(4000); // 2 items * 2 quantity * 1000 price
14    assertThat(result.getStatus()).isEqualTo(OrderStatus.COMPLETED);
15}

(README.md:172-189)

ArbitraryBuilders 유틸리티

ArbitraryBuilders 클래스는 여러 ArbitraryBuilder를 조합하는 유틸리티 메서드를 제공한다. zip 메서드를 통해 여러 빌더의 결과를 결합할 수 있다.

java
1// 두 ArbitraryBuilder 조합
2public static <T, U, R> ArbitraryBuilder&lt;R&gt; zip(
3    ArbitraryBuilder&lt;T&gt; a1,
4    ArbitraryBuilder&lt;U&gt; a2,
5    BiFunction<T, U, R> combinator
6)
7
8// 리스트로 조합
9public static &lt;R&gt; ArbitraryBuilder&lt;R&gt; zip(
10    List<ArbitraryBuilder<?>> list,
11    Function<List<?>, R> combinator
12)

(fixture-monkey/src/main/java/com/navercorp/fixturemonkey/ArbitraryBuilders.java:28-70)

적용 시나리오

단위 테스트 객체 생성

복잡한 도메인 객체를 테스트하기 위해 수동으로 setter를 호출하는 대신, Fixture Monkey를 사용하여 자동으로 생성할 수 있다. 특히 생성자나 빌더 패턴이 복잡한 경우에 유용하다.

프로퍼티 기반 테스트

Jqwik과 통합하여 프로퍼티 기반 테스트를 수행할 수 있다. 각 테스트 실행마다 다른 데이터가 생성되어 엣지 케이스를 발견하기 쉽다.

통합 테스트 데이터 준비

데이터베이스나 외부 API와의 통합 테스트에서 필요한 테스트 데이터를 쉽게 생성할 수 있다. 경로 기반 설정을 통해 연관된 객체들의 속성도 일관되게 설정할 수 있다.

테스트 코드 리팩토링

기존의 중복된 테스트 픽스처 생성 코드를 ArbitraryBuilder로 추출하여 재사용할 수 있다. 테스트 코드의 가독성과 유지보수성이 향상된다.

보고서 읽기 가이드

正在加载图表渲染器...

추천 읽기 순서:

  1. 프로젝트 개요 (현재 문서): Fixture Monkey의 전반적인 소개와 핵심 개념 파악
  2. 핵심 기능 심화: 경로 표현식, 조작자, 제약 조건 등 상세 기능 학습
  3. 아키텍처 상세: 내부 구현 원리와 확장 포인트 이해
  4. API 레퍼런스: 각 클래스와 메서드의 상세 스펙 확인
  5. 실전 예제: 다양한 사용 시나리오와 모범 사례 학습
  6. 플러그인 확장: Kotlin, Jackson, Jakarta Bean Validation 등 플러그인 활용
  7. 성능 최적화: 대규모 테스트 환경에서의 성능 튜닝

프로젝트 핵심 능력 지표

지표수치/내용
지원 언어2개 (Java, Kotlin)
최소 JDK 버전1.8
핵심 모듈 수4개 이상 (core, benchmarks, plugins 등)
API 진입점2개 (FixtureMonkey.create, FixtureMonkey.builder)
핵심 인터페이스ArbitraryBuilder (set, sample, size 등)
기본 컬렉션 크기 범위0-3 (설정 가능)
운영 검증10,000개 이상의 테스트 지원 (Naver 결제 서비스)
플러그인 생태계Kotlin, IntelliJ Helper 등
문서화 언어2개 (English, Korean)

(README.md:1-220, fixture-monkey/src/main/java/com/navercorp/fixturemonkey/Constants.java:20-28)