본문으로 건너뛰기
버전: v1.0.x

InnerSpec

InnerSpec은 적용하려는 커스터마이징에 대한 타입 독립적인 명세입니다. ArbitraryBuilder 내의 setInner() 메서드를 사용하면 InnerSpec 인스턴스에 정의된 명세를 빌더에 적용할 수 있습니다.

InnerSpec 에는 커스터마이징 세부 정보가 저장되며 여러 ArbitraryBuilder에서 재사용할 수 있습니다. ArbitraryBuilder에서 픽스처 몽키 표현식을 사용하는 방식과 달리 InnerSpec은 중첩된 구조를 사용해 프로퍼티에 접근이 가능합니다.

InnerSpec 의 또 다른 장점은 일반적인 표현식과 달리 맵 프로퍼티를 커스터마이징할 수 있다는 점입니다.

Kotlin EXP 는 InnerSpec에서 지원하지 않습니다. InnerSpec은 타입 독립적으로 설계되었기 때문에, 프로퍼티 이름을 통해 프로퍼티를 접근해야 합니다.

ArbitraryBuilder 에 InnerSpec 적용하기

빌더에 미리 정의된 InnerSpec 을 적용하려면 다음과 같이 setInner() 메서드를 사용하세요.

InnerSpec innerSpec = new InnerSpec().property("id", 1000);

fixtureMonkey.giveMeBuilder(Product.class)
.setInner(innerSpec);

프로퍼티 커스터마이징하기

property()

ArbitraryBuilder 의 set() 메서드와 유사하게, 프로퍼티 이름과 원하는 값을 지정하여 프로퍼티를 커스터마이징할 수 있습니다.

위험

요소([]) 또는 중첩 필드(.)를 참조하는 Fixture Monkey 표현식은 프로퍼티 이름으로 사용할 수 없습니다. 프로퍼티 이름 자체만 사용할 수 있습니다.

InnerSpec innerSpec = new InnerSpec()
.property("id", 1000);

size(), minSize(), maxSize()

size(), minSize(), 그리고 maxSize() 는 프로퍼티의 크기를 지정하는 데 사용할 수 있습니다.

앞서 언급했듯이, InnerSpec 은 중첩된 방식으로 명세을 정의합니다. property() 를 사용하여 컨테이너 프로퍼티를 먼저 선택한 다음, 내부에 정의된 innerSpec 컨슈머를 사용하여 크기를 설정할 수 있습니다.

InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.size(5)); // size:5

InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.size(3, 5)); // minSize:3, maxSize:5

InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.minSize(3)); // minSize:3

InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.maxSize(5)); // maxSize:5

postCondition()

postCondition() 은 프로퍼티가 특정 조건을 만족해야 하는 경우 사용할 수 있습니다.

위험

setPostCondition 의 조건을 너무 좁게 설정하면, 생성 비용이 매우 높아질 수 있습니다. 이런 경우 set 을 사용해주세요.

InnerSpec innerSpec = new InnerSpec()
.property("id", id -> id.postCondition(Long.class, it -> it > 0));

inner()

또한 inner() 를 사용하여 미리 정의된 InnerSpec 을 사용하여 프로퍼티를 커스터마이징할 수 있습니다.

InnerSpec innerSpec = new InnerSpec()
.property("id", 1000L);

fixtureMonkey.giveMeBuilder(Product.class)
.setInner(
new InnerSpec()
.property("nestedObject", nestedObject -> nestedObject.inner(innerSpec))
);

리스트 커스터마이징하기

listElement()

목록 내의 개별 요소는 listElement()를 사용하여 선택할 수 있습니다. 이는 픽스처 몽키 표현식을 사용하여 "[n]"으로 요소를 참조하는 것과 동일합니다.

InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.listElement(0, "red"));

allListElement()

만약 목록의 모든 요소를 동시에 설정하려면 allListElement()를 사용할 수 있습니다. 이는 픽스처 몽키 표현식을 사용하여 "[*]"로 요소를 참조하는 것과 동일합니다.

InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.allListElement("red"));

맵 커스터마이징하기

InnerSpec은 맵 프로퍼티 엔트리를 커스터마이징하기 위해 특별한 메소드를 제공합니다.

위험

맵 프로퍼티의 크기를 먼저 지정하지 않고 맵 엔트리를 설정하면 변경이 일어나지 않을 수 있습니다. 값을 설정하기 전에 맵 프로퍼티가 의도한 크기인지 확인해주세요.

key(), value(), entry()

key(), value(), entry() 메소드를 사용하여 맵 프로퍼티 엔트리를 커스터마이징할 수 있습니다. key()를 사용하면 맵 엔트리의 키에 지정된 값을 할당하고, 엔트리의 값은 무작위로 설정됩니다. 마찬가지로, value()를 사용하면 맵 엔트리의 값에 지정된 값을 할당하고, 키는 무작위로 설정됩니다. 키와 값을 동시에 지정하려면 entry()를 사용할 수 있습니다.

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.key(1000));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.value("ABC Store"));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.entry(1000, "ABC Store"));

keys(), values(), entries()

맵 내의 여러 개의 엔트리를 설정할 때 keys(), values(), entries()를 사용하여 여러 값을 전달할 수 있습니다.

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.keys(1000, 1001, 1002));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.values("ABC Store", "123 Convenience", "XYZ Mart"));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.entries(1000, "ABC Store", 1001, "123 Convenience", 1002, "XYZ Mart"));

allKey(), allValue(), allEntry()

allListElement()와 유사하게, allKey(), allValue(), allEntry()를 사용하여 맵 내의 모든 엔트리를 지정된 값으로 설정할 수 있습니다.

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.allKey(1000));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.allValue("ABC Store"));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.allEntry(1000, "ABC Store"));

keyLazy(), valueLazy(), entryLazy()

ArbitraryBuilder의 setLazy() 메소드와 유사하게, Supplier를 전달하여 값을 할당할 수 있습니다. Supplier는 InnerSpec이 적용된 ArbitraryBuilder가 샘플링될 때마다 실행됩니다.

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.keyLazy(this::generateMerchantKey));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.valueLazy(this::generateMerchantValue));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.entryLazy(this::generateMerchantKey, this::generateMerchantValue));

allKeyLazy(), allValueLazy(), allEntryLazy()

allKey() 메소드와 마찬가지로, allKeyLazy()를 사용하여 맵 내의 모든 엔트리에 keyLazy()를 적용할 수 있습니다. allValueLazy()allEntryLazy()도 유사하게 작동합니다.

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.allKeyLazy(this::generateMerchantKey));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.allValueLazy(this::generateMerchantValue));

InnerSpec innerSpec = new InnerSpec()
.property("merchantInfo", merchantInfo -> merchantInfo.allEntryLazy(this::generateMerchantKey, this::generateMerchantValue));

중첩된 맵 커스터마이징하기

메서드를 조합하여 InnerSpec 내에서 맵의 키, 값 또는 둘 다를 효과적으로 커스터마이징할 수 있습니다.

다음과 같이 중첩된 맵 구조의 시나리오를 고려해보겠습니다.

public class Example {
Map<Map<String, String>, String> mapByString;
Map<String, Map<String, String>> stringByMap;
}

맵 타입의 키 설정

맵 타입의 키를 설정하려면 key()를 사용하여 맵 키에 접근한 다음, 해당 키를 추가로 커스터마이징할 수 있습니다.

InnerSpec().property("mapByString", m -> m.key(k -> k.entry("key", "value")));

만약 엔트리 자체를 설정해야 하는 경우, entry()로 엔트리에 접근하고 InnerSpec을 사용하여 키를 추가로 커스터마이징한 다음, 특정 값을 설정합니다.

InnerSpec().property("mapByString", m -> m.entry(k -> k.entry("innerKey", "innerValue")), "value")

맵 타입의 값 설정

map 타입의 값이 있는 맵의 경우, value()를 사용하여 맵 값을 접근한 다음, 해당 값을 추가로 커스터마이징할 수 있습니다.

InnerSpec().property("stringByMap", m -> m.value(v -> v.entry("key", "value")))

만약 엔트리 자체를 설정해야 하는 경우, entry()로 엔트리에 접근하고 InnerSpec을 사용하여 키를 추가로 커스터마이징한 다음, 특정 값을 설정합니다.

InnerSpec().property("stringByMap", m -> m.entry("key", v -> v.entry("innerKey", "innerValue")))