인터페이스 커스터마이징

인터페이스에서 ArbitraryBuilder의 모든 API를 사용할 수 있습니다. 우리는 이미 Generating Interface Type 에서 API를 사용한 예를 확인했었습니다. 알아본 내용을 복습하면, 인터페이스의 종류에는 interface, generic interface ,selaed interface이 있습니다. 인터페이스의 종류와 상관없이 모든 인터페이스의 프로퍼티를 제어할 수 있습니다.

public interface StringSupplier {
	String getValue();
}

FixtureMonkey fixture = FixtureMonkey.create();

String result = fixture.giveMeBuilder(StringSupplier.class)
	.set("value", "fix")
	.sample()
	.getValue();

인터페이스를 생성하는 ArbitraryBuilder가 제어할 수 있는 프로퍼티는 실제로 생성한 구현체마다 다릅니다. 하지만 아직은 구현체를 선택할 수 있는 ArbitraryBuilder API가 존재하지 않습니다. 인터페이스가 하나의 구현체를 가지고 있다면 구현체 프로퍼티도 제어가 가능합니다. 하지만 구현체가 두 개 이상이라면 인터페이스의 프로퍼티만 제어가 가능합니다.

원하는 구현체를 랜덤하게 생성할 수는 없지만 이미 구현체의 인스턴스가 있다면 원하는 구현체를 set API를 사용해 생성할 수 있습니다. interfaceImplements 옵션을 사용한 경우interfaceImplements 옵션을 사용하지 않은 경우 두 경우로 나누어 설명을 해보겠습니다.

옵션을 사용한 경우

인터페이스 타입은 set API로 설정한 구현체로 생성합니다. 구현체는 interfaceImplements 옵션에 등록을 해야 합니다.

public interface ObjectValueSupplier {
	Object getValue();
}

public class StringValueSupplier implements ObjectValueSupplier {
	private final String value;

	@ConstructorProperties("value") // 롬복을 사용하면 추가하지 않아도 됩니다.
	public StringValueSupplier(String value) {
		this.value = value;
	}

	@Override
	public String getValue() {
		return value;
	}
}

public class IntegerValueSupplier implements ObjectValueSupplier {
	private final int value;
	private final int implementationValue;

	@ConstructorProperties({"value", "implementationValue"}) // 롬복을 사용하면 추가하지 않아도 됩니다.
	public IntegerValueSupplier(int value, int implementationValue) {
		this.value = value;
		this.implementationValue = implementationValue;
	}

	@Override
	public Integer getValue() {
		return value;
	}

	public int getImplementationValue() {
		return implementationValue;
	}
}

FixtureMonkey fixture = FixtureMonkey.builder()
	.objectIntrospector(
		ConstructorPropertiesArbitraryIntrospector.INSTANCE) // 구현체를 인스턴스화할 때 사용합니다.
	.plugin(
		new InterfacePlugin()
			.interfaceImplements(
				ObjectValueSupplier.class,
				List.of(StringValueSupplier.class, IntegerValueSupplier.class)
            )
	)
	.build();

IntegerValueSupplier integerValueSupplier = (IntegerValueSupplier)fixture.giveMeBuilder(ObjectValueSupplier.class)
	.set("$", new IntegerValueSupplier(-1203))
	.sample();

구현체의 프로퍼티도 제어할 수 있습니다.

IntegerValueSupplier integerValueSupplier = (IntegerValueSupplier)fixture.giveMeBuilder(ObjectValueSupplier.class)
	.set("$", new IntegerValueSupplier(-1203, 1203))
	.set("implementationValue", 1) // it works.
	.sample();

Without the option

원하는 구현체를 설정하기 위해서는 set API 를 특별한 방식으로 사용해야 합니다. 구현체 인스턴스를 Values.just로 감싸서 입력해야 합니다.

public interface ObjectValueSupplier {
	Object getValue();
}

public class StringValueSupplier implements ObjectValueSupplier {
	private final String value;

	@ConstructorProperties("value") // 롬복을 사용하면 추가하지 않아도 됩니다.
	public StringValueSupplier(String value) {
		this.value = value;
	}

	@Override
	public String getValue() {
		return value;
	}
}

public class IntegerValueSupplier implements ObjectValueSupplier {
	private final int value;

	@ConstructorProperties("value") // 롬복을 사용하면 추가하지 않아도 됩니다.
	public IntegerValueSupplier(int value) {
		this.value = value;
	}

	@Override
	public Integer getValue() {
		return value;
	}
}

FixtureMonkey fixture = FixtureMonkey.builder()
	.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE) // 구현체를 인스턴스화할 때 사용합니다.
	.build();

IntegerValueSupplier integerValueSupplier = (IntegerValueSupplier)fixture.giveMeBuilder(ObjectValueSupplier.class)
	.set("$", Values.just(new IntegerValueSupplier(-1203)))
	.sample();

픽스쳐 몽키는 interfaceImplements 옵션으로 등록하지 않은 구현체의 프로퍼티를 알 수 없습니다. Values.just를 사용한 경우 프로퍼티를 제어할 수 없습니다.

IntegerValueSupplier integerValueSupplier = (IntegerValueSupplier)fixture.giveMeBuilder(ObjectValueSupplier.class)
    .set("$", Values.just(new IntegerValueSupplier(-1203)))
    .set("value", 1) // not works
    .sample();