Closed YongGoose closed 3 months ago
@YongGoose 안녕하세요.
유일한 값을 생성하는 방법에는 여러 가지 방법이 있습니다. 말씀주신 케이스는 하나의 테스트 케이스 내에서 하나의 타입 (Adate)의 여러 인스턴스를 생성할 때 유일한 값이 필요한 케이스라고 이해했습니다.
그런 경우에는 다음과 같이 설정하면 유일한 id를 보장할 수 있습니다.
var adates = fixtureMonkey.giveMeBuilder(Adate.class)
.setNull("tag")
.setNull("member")
.set("id", Values.just(CombinableArbitrary.from(() -> Arbitraries.longs().sample()).unique()))
.setNotNull("id")
.sampleList(1_000);
동일한 동작을 하는 사용자 친화적인 API를 이후 버전에 추가할 예정입니다. API의 형태를 고민하고 있는 중이라 혹시 제안주실 API 형태가 있다면 말씀주시면 감사하겠습니다!
혹시 원하시는대로 동작이 안되는 케이스가 더 있다면 공유해주세요!
감사합니다.
@seongahjo
여러 가지 형태의 API를 고려해본 결과, seed
와 같이 사용자가 값을 설정할 수 있는 API가 사용자 친화적인 것 같습니다.
seed
방법은 object-mother 패턴을 이용하고 있는 EasyRandom에서 사용하고 있는 방식입니다.
간단히 설명하자면, EasyRandom
객체를 생성할 때 EasyRandomParameters
를 생성자로 전달할 수 있습니다. 이 EasyRandomParameters
에서는 seed
값을 설정할 수 있는데, 이 값은 EasyRandom
객체의 생성자를 통해 Random
객체의 seed 값으로 할당됩니다.
public class EasyRandom extends Random {
...
public EasyRandom(final EasyRandomParameters easyRandomParameters) {
Objects.requireNonNull(easyRandomParameters, "Parameters must not be null");
// super.setSeed를 통해 Random에 Seed를 할당합니다.
super.setSeed(easyRandomParameters.getSeed());
LinkedHashSet<RandomizerRegistry> registries = setupRandomizerRegistries(easyRandomParameters);
RandomizerProvider customRandomizerProvider = easyRandomParameters.getRandomizerProvider();
randomizerProvider = customRandomizerProvider == null ? new RegistriesRandomizerProvider() : customRandomizerProvider;
randomizerProvider.setRandomizerRegistries(registries);
objectFactory = easyRandomParameters.getObjectFactory();
arrayPopulator = new ArrayPopulator(this);
CollectionPopulator collectionPopulator = new CollectionPopulator(this);
MapPopulator mapPopulator = new MapPopulator(this, objectFactory);
OptionalPopulator optionalPopulator = new OptionalPopulator(this);
enumRandomizersByType = new ConcurrentHashMap<>();
fieldPopulator = new FieldPopulator(this,
this.randomizerProvider, arrayPopulator,
collectionPopulator, mapPopulator, optionalPopulator);
exclusionPolicy = easyRandomParameters.getExclusionPolicy();
parameters = easyRandomParameters;
}
할당을 한 뒤, objects를 통해 생성을 하면 seed가 같을 때 같은 행동이 보장됩니다.
public <T> Stream<T> objects(final Class<T> type, final int streamSize) {
if (streamSize < 0) {
throw new IllegalArgumentException("The stream size must be positive");
}
return Stream.generate(() -> nextObject(type)).limit(streamSize);
}
코드 링크 첨부하겠습니다. EasyRandomParameters.seed EasyRandom. constructor
FixtureMonkey에서는 객체 생성을 동일하게 할 수 있는 여러 가지 방법을 제공합니다. (ex: ArbitraryBuilder
- fixed
)
하지만 이러한 방법은 객체의 생성만 동일하게 만들기 때문에 sampleList와 같은 API를 사용할 경우 모든 객체의 값이 동일해지는 문제가 발생할 수 있습니다.
이와 같은 문제를 해결하기 위해, java.util.Random을 사용하는 방법을 고민해보았습니다. Random 클래스는 시드(seed) 값을 고정하면 동일한 패턴의 난수를 생성합니다. 이 난수를 이용해 ArbitraryContainerInfo
의 fixedSize를 설정하면 동일한 동작을 보장할 수 있을 것이라고 생각합니다.
//seed
public ArbitraryBuilder<T> seed(long seed) {
Random random = new Random(seed);
this.context.getContainerInfoManipulators().forEach(manipulator -> manipulator.setFixedSize(random.nextInt()));
this.context.markFixed();
return this;
}
---
public final class ContainerInfoManipulator {
...
public void setFixedSize(int fixedSize) {
this.containerInfo = new ArbitraryContainerInfo(
fixedSize,
fixedSize
);
}
여러 조건을 깊이 고민하지 않은 단순한 접근 방식이므로 예상치 못한 이슈가 있을 수 있습니다... ^_^ 이 방법이 괜찮으시다면, 조금 더 고민해본 뒤 Feature Request 이슈로 등록하겠습니다!
@YongGoose 제안 감사합니다!
엇, 제가 잘못 이해한 걸수도 있는데요. seed
를 설정하는 게 unique한 값을 생성하는 데 어떻게 도움을 줄 수 있을까요??
seed
설정이 필요하다는 제안에는 저도 동의합니다. 다만 아래 작업이 선행되어야 의미가 있을 거라고 생각하고 있긴 합니다. https://github.com/naver/fixture-monkey/issues/990
동일한 동작을 하는 사용자 친화적인 API를 이후 버전에 추가할 예정입니다. API의 형태를 고민하고 있는 중이라 혹시 제안주실 API 형태가 있다면 말씀주시면 감사하겠습니다!
동일한 동작을 하는 API에 대한 제안이었습니다🙂 혹시나 제가 질문을 잘못 이해했다면 말씀해주세요..!
Describe your question
AS-IS
다음과 같이 중복된 값이 들어가면 안 되는 필드가 있을 때
위 코드를 통해 1,000건의 객체를 생성해본 결과 81건 정도의 데이터가 중복되었다고 메시지가 출력됐습니다. 출력 메시지
TO-BE
여러 건의 데이터를 생성했을 때 id와 같이 중복된 값이 있으면 안 되는 필드에는 고유한 값이 들어가게 하고 싶습니다.
EasyRandom과 같은 다른 object mother 방법을 사용하는 라이브러리들을 이용해 같은 로직을 구현해보았는데 같은 이슈가 발생했습니다. (독립적으로 샘플을 생성해, 때문에 중복이 발생할 수밖에 없는 것 같습니다)
Fixture-monkey의 sampleList도 각각의 샘플을 독립적으로 랜덤하게 생성하기 때문에 다른 샘플들과 값을 비교할 수 없어 중복이 발생할 수밖에 없다고 이해했는데, 맞을까요?
만약 제가 맞게 이해했다면, 이 이슈를 닫겠습니다 :)
Your environment
version of Fixture Monkey: 10.20 version of Java/Kotlin: Java 17