속성 기반 테스트 (Property-based Testing)

Dahun Yoo·2023년 11월 10일
1

QA or Test

목록 보기
38/38

업로드중..
오늘은 속성 기반 테스트(Property based testing)에 대해 기재해봅니다.

종래의 테스트 기법들은...

저의 포스트들에도 많이 기재되어있지만, 종래에, 많이 사용되는 테스트기법들은 대부분 예제 기반 테스트(example based testing) 입니다.

예제 기반 테스트란, 대부분의 경우에 어떤 로직이 정상적으로 동작하는지 확인하기 위해, 대략적으로 아래의 기준에 해당하는 예시 입력값 을 선정합니다.

  • 정상적인 입력값이며 정상적인(true) 응답값이 나올만한 값
  • 정상적인 입력값이며 비정상적인(false) 응답값이 나올만한 값
  • 비정상적인 입력값(Exception or Error)

그리고 그 입력값에 맞는 적절한 예상 결과값 을 선정한 후 테스트를 돌려보는 식입니다.

흔히들 유닛테스트에서 많이 작성하는 그런 테스트라고도 할 수 있을 것입니다.

코드로 적당히 기재하면 아래와 같을 것 입니다.

def divide(a:int, b:int)->int:
	return a/b
    
assert divide(4, 2) == 2
assert divide(4, 2) != 3
with pytest.raises(ZeroDivisionError):
	assert divide(4, 0) 

이러한 방법의 문제로는, 예상했던 값 이외의 어떠한 엣지케이스를 발견하기 힘들다는 점입니다.
물론 여러가지 커버리지 측정방법으로 어느정도의 품질을 기대할 순 있겠으나, 극단적으로 말하자면 버그를 찾아내었다고해도 버그가 완전히 없냐고 한다면 그렇게 말할 순 없는 것과 동일한 셈입니다.

속성 기반 테스트

Property testing
Not to be confused with property testing algorithms.

Property testing is a testing technique where, instead of asserting that specific inputs produce specific expected outputs, the practitioner randomly generates many inputs, runs the program on all of them, and asserts the truth of some "property" that should be true for every pair of input and output. For example, every output from a serialization function should be accepted by the corresponding deserialization function, and every output from a sort function should be a monotonically increasing list containing exactly the same elements as its input.

Property testing libraries allow the user to control the strategy by which random inputs are constructed, to ensure coverage of degenerate cases, or inputs featuring specific patterns that are needed to fully exercise aspects of the implementation under test.

Property testing is also sometimes known as "generative testing" or "QuickCheck testing" since it was introduced and popularized by the Haskell library QuickCheck.

그래서 나오게 된 테스트 방법이, 이러한 예제가 아니라 속성값에 기반한 테스트 방법입니다. 구체적인 예시 대신에 랜덤하게, 프로그램이 지켜야할 어떠한 속성의 범위값을 정의를 하고, 그 범위값을 넘어서서 이슈가 발생할만한 값을 찾아 테스트를 실행하는 것입니다. 때문에 다양한 파라미터의 값으로 반복적으로 테스트를 수행해볼 수 있을 것입니다.

간단한 예시

예시 기반 테스팅

아래 합격 등급을 판별하는 간단한 코드를 예시로 설명하자면..

public class PassingGrade {
	public boolean passed(float grade) {
    	if (grade < 1.0 || grade > 10.0) throw new IllegalArgumentException();
        return grade >= 5.0;
    }
}

기존의 테스트의 방법대로면 조건문에 해당하는 input들을 넣어보면서 기대하는 결과값이 출력되는지를 확인할 것 입니다.

  • grade가 1.0미만일 경우 익셉션이 발생한다.
  • grade가 정확히 1.0일 경우 익셉션이 발생한다.
  • grade가 정확히 10.0일 경우 true를 리턴한다.
  • grade가 10.0을 초과하는 경우 익셉션이 발생한다.
  • grade가 5.0 미만인 경우에는 false를 리턴한다.
  • grade가 정확히 5.0인 경우에는 true를 리턴한다.
  • grade가 5.0 이상이면서 10.0인 경우에는 true를 리턴한다.

이렇게 어떠한 기대값이 나올만한 값들을 파라미터로 전달하면서 기댓값을 확인하는 예시 기반 테스트의 경우에는 경곗값테스트를 포함하여 최소한 7개의 테스트가 작성되어야할 것입니다.

속성 기반 테스팅

반면 속성 기반 테스팅방법으로 위 코드를 검증한다고 한다면, 크게 아래와 같이 분류를 해볼 수 있을 것 입니다.

  • fail이 리턴되는 패턴
  • true가 리턴되는 패턴
  • exception이 발생되는 패턴

각각이 발생할만한 입력값들에 대해, 범위를 제한해주고 랜덤한 파라미터들을 전달해서 테스트를 해보는 것입니다. (특정 라이브러리를 사용해서 자동으로 랜덤파라미터들을 생성할 수 있음)

이렇게 테스트에 필요한 속성값들에 대해 랜덤한 값들을 넘겨서 놓칠만한 엣지케이스를 찾으려고 시도하는 것이, 속성 기반 테스팅입니다.

속성 기반 테스팅의 어려운 점

테스트하고자 하는 로직에 따라서는 기댓값에 대한 정의가 어려울 수 있다는 점입니다.
구체적인 입력값의 범위 등을 정의하지않는다면, 랜덤하게 입력되는 값들에 대해 예상 동작을 미리 선언하는 것은 어렵기 떄문입니다. 입력받아야할 데이터들에 대해서 어느정도 성격을 부여하여 범위를 정의하고, 정의된 범위/성격의 데이터가 입력되면 어떤 값을 예상할 수 있을지에 대해 추상화가 이루어져야합니다.

ref

profile
QA Engineer

0개의 댓글