InnerSpec
InnerSpec은 적용하려는 커스터마이징에 대한 타입 독립적인 명세입니다.
ArbitraryBuilder 내의 setInner() 메서드를 사용하면 InnerSpec 인스턴스에 정의된 명세를 빌더에 적용할 수 있습니다.
InnerSpec 에는 커스터마이징 세부 정보가 저장되며 여러 ArbitraryBuilder에서 재사용할 수 있습니다.
ArbitraryBuilder에서 픽스처 몽키 표현식을 사용하는 방식과 달리 InnerSpec은 중첩된 구조를 사용해 프로퍼티에 접근이 가능합니다.
InnerSpec 의 또 다른 장점은 일반적인 표현식과 달리 맵 프로퍼티를 커스터마이징할 수 있다는 점입니다.
ArbitraryBuilder 에 InnerSpec 적용하기
빌더에 미리 정의된 InnerSpec 을 적용하려면 다음과 같이 setInner() 메서드를 사용하세요.
InnerSpec innerSpec = new InnerSpec().property("id", 1000);
fixtureMonkey.giveMeBuilder(Product.class)
.setInner(innerSpec);val innerSpec = InnerSpec().property("id", 1000)
fixtureMonkey.giveMeBuilder<Product>()
.setInner(innerSpec)프로퍼티 커스터마이징하기
property()
ArbitraryBuilder 의 set() 메서드와 유사하게, 프로퍼티 이름과 원하는 값을 지정하여 프로퍼티를 커스터마이징할 수 있습니다.
InnerSpec innerSpec = new InnerSpec()
.property("id", 1000);val innerSpec = 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
val innerSpec = InnerSpec()
.property("options") { it.size(5) } // size:5
val innerSpec = InnerSpec()
.property("options") { it.size(3, 5) } // minSize:3, maxSize:5
val innerSpec = InnerSpec()
.property("options") { it.minSize(3) } // minSize:3
val innerSpec = InnerSpec()
.property("options") { it.maxSize(5) } // maxSize:5postCondition()
postCondition() 은 프로퍼티가 특정 조건을 만족해야 하는 경우 사용할 수 있습니다.
InnerSpec innerSpec = new InnerSpec()
.property("id", id -> id.postCondition(Long.class, it -> it > 0));val innerSpec = InnerSpec()
.property("id") { it.postCondition(Long::class.java) { 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))
);val innerSpec = InnerSpec()
.property("id", 1000L)
fixtureMonkey.giveMeBuilder<Product>()
.setInner(
InnerSpec()
.property("nestedObject") { it.inner(innerSpec) }
)리스트 커스터마이징하기
listElement()
목록 내의 개별 요소는 listElement()를 사용하여 선택할 수 있습니다.
이는 픽스처 몽키 표현식을 사용하여 “[n]“으로 요소를 참조하는 것과 동일합니다.
InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.listElement(0, "red"));val innerSpec = InnerSpec()
.property("options") { it.listElement(0, "red") }allListElement()
만약 목록의 모든 요소를 동시에 설정하려면 allListElement()를 사용할 수 있습니다.
이는 픽스처 몽키 표현식을 사용하여 “[*]“로 요소를 참조하는 것과 동일합니다.
InnerSpec innerSpec = new InnerSpec()
.property("options", options -> options.allListElement("red"));val innerSpec = InnerSpec()
.property("options") { it.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"));val innerSpec = InnerSpec()
.property("merchantInfo") { it.key(1000) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.value("ABC Store") }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.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"));val innerSpec = InnerSpec()
.property("merchantInfo") { it.keys(1000, 1001, 1002) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.values("ABC Store", "123 Convenience", "XYZ Mart") }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.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"));val innerSpec = InnerSpec()
.property("merchantInfo") { it.allKey(1000) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.allValue("ABC Store") }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.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));val innerSpec = InnerSpec()
.property("merchantInfo") { it.keyLazy(this::generateMerchantKey) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.valueLazy(this::generateMerchantValue) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.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));val innerSpec = InnerSpec()
.property("merchantInfo") { it.allKeyLazy(this::generateMerchantKey) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.allValueLazy(this::generateMerchantValue) }
val innerSpec = InnerSpec()
.property("merchantInfo") { it.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")));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")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")))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")))InnerSpec().property("stringByMap") { m -> m.entry("key") {v -> v.entry("innerKey", "innerValue")} }