1. 개요
이 기사에서는 Property Testing 의 개념과 vavr-test 라이브러리 에서의 구현에 대해 살펴보겠습니다 .
속성 기반 테스트 (PBT)를 사용하면 프로그램 이 준수해야 하는 불변성에 관한 상위 수준 동작을 지정할 수 있습니다.
2. 속성 테스트란 무엇입니까?
속성은 불변과 입력 값 생성기 의 조합입니다 . 생성된 각 값에 대해 불변은 조건자로 처리되고 해당 값에 대해 true 또는 false를 생성하는지 여부를 확인합니다.
false를 생성하는 값이 하나 있는 즉시 속성이 위조되었다고 하며 검사가 중단됩니다. 특정 양의 샘플 데이터 후에 속성을 무효화할 수 없으면 속성이 충족된 것으로 간주됩니다.
이러한 동작 덕분에 불필요한 작업을 수행하지 않고 조건이 충족되지 않으면 테스트가 빠르게 실패합니다.
3. 메이븐 의존성
먼저 vavr-test 라이브러리에 Maven 의존성을 추가해야 합니다.
<dependency>
<groupId>io.vavr</groupId>
<artifactId>jvavr-test</artifactId>
<version>${vavr.test.version}</version>
</dependency>
<properties>
<vavr.test.version>2.0.5</vavr.test.version>
</properties>
4. 속성 기반 테스트 작성
문자열 스트림을 반환하는 함수를 생각해 봅시다. 간단한 규칙에 따라 숫자를 문자열에 매핑하는 0 위쪽의 무한 스트림입니다. 우리는 여기에서 Pattern Matching 이라는 흥미로운 Vavr 기능을 사용하고 있습니다 .
private static Predicate<Integer> divisibleByTwo = i -> i % 2 == 0;
private static Predicate<Integer> divisibleByFive = i -> i % 5 == 0;
private Stream<String> stringsSupplier() {
return Stream.from(0).map(i -> Match(i).of(
Case($(divisibleByFive.and(divisibleByTwo)), "DividedByTwoAndFiveWithoutRemainder"),
Case($(divisibleByFive), "DividedByFiveWithoutRemainder"),
Case($(divisibleByTwo), "DividedByTwoWithoutRemainder"),
Case($(), "")));
}
이러한 메서드에 대한 단위 테스트를 작성하면 오류가 발생하기 쉽습니다. 왜냐하면 우리가 일부 극단적인 경우를 잊어버리고 기본적으로 모든 가능한 시나리오를 다루지 않을 가능성이 높기 때문입니다.
다행스럽게도 우리는 모든 경우를 다룰 수 있는 속성 기반 테스트를 작성할 수 있습니다. 먼저 테스트에 어떤 종류의 숫자를 입력해야 하는지 정의해야 합니다.
Arbitrary<Integer> multiplesOf2 = Arbitrary.integer()
.filter(i -> i > 0)
.filter(i -> i % 2 == 0 && i % 5 != 0);
우리는 입력 숫자가 두 가지 조건을 충족해야 한다고 지정했습니다. 즉, 0보다 커야 하고 나머지 없이 2로 나눌 수 있어야 하지만 5로는 나눌 수 없어야 합니다.
다음으로 테스트된 함수가 주어진 인수에 대해 적절한 값을 반환하는지 확인하는 조건을 정의해야 합니다.
CheckedFunction1<Integer, Boolean> mustEquals
= i -> stringsSupplier().get(i).equals("DividedByTwoWithoutRemainder");
속성 기반 테스트를 시작하려면 Property 클래스 를 사용해야 합니다 .
CheckResult result = Property
.def("Every second element must equal to DividedByTwoWithoutRemainder")
.forAll(multiplesOf2)
.suchThat(mustEquals)
.check(10_000, 100);
result.assertIsSatisfied();
우리는 2의 배수인 모든 랜덤의 정수에 대해 mustEquals 술어가 충족되어야 한다고 지정하고 있습니다. check() 메서드는 생성된 입력 의 크기와 이 테스트가 실행될 횟수를 사용합니다.
나머지 없이 2와 5로 나눌 수 있는 모든 입력 숫자에 대해 stringsSupplier() 함수가 DividedByTwoAndFiveWithoutRemainder 문자열 을 반환 하는지 확인하는 또 다른 테스트를 빠르게 작성할 수 있습니다 .
임의 Provider와 CheckedFunction 을 변경해야 합니다 .
Arbitrary<Integer> multiplesOf5 = Arbitrary.integer()
.filter(i -> i > 0)
.filter(i -> i % 5 == 0 && i % 2 == 0);
CheckedFunction1<Integer, Boolean> mustEquals
= i -> stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder");
그런 다음 속성 기반 테스트를 1,000회 반복 실행할 수 있습니다.
Property.def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder")
.forAll(multiplesOf5)
.suchThat(mustEquals)
.check(10_000, 1_000)
.assertIsSatisfied();
5. 결론
이 빠른 기사에서 우리는 속성 기반 테스트의 개념을 살펴보았습니다.
우리는 vavr -test 라이브러리를 사용하여 테스트를 만들었습니다. Arbitrary, CheckedFunction 및 Property 클래스를 사용 하여 vavr-test 를 사용하여 속성 기반 테스트를 정의했습니다 .
이러한 모든 예제와 코드 스니펫의 구현은 GitHub 에서 찾을 수 있습니다. 이것은 Maven 프로젝트이므로 있는 그대로 쉽게 가져오고 실행할 수 있어야 합니다.