테스트 케이스 제작 도구 제작기 (애증의 Allpairs.py)

테스트 설계 기법의 기본은 조건의 조합에 달려 있습니다.

테스트 설계 방법을 공부한 적이 있는 분은 어느 정도 공감할 수 있다고 생각합니다. 경계치 분석, 동치 분할은 그렇지 않지만 결정 테이블, 상태 천이는 물론, 코드 베이스 설계 수법도 TRUE와 FALSE의 조합입니다.

인기 있는 언어의 Java나 Python으로 그런 조합 라이브러리가 있을 것입니다. 저는 Python 친숙하기 때문에 PyPI로 검색해 보았습니다. 역시 있었습니다 1 .

소스 코드에서 조건 (if, while 등)을 읽고 조합을 만들었습니다. 예를 들면 if (A>0 || B==0){ //decision #1 statement1; } if (C>0 && D==0){ //decision #2 statement2; } 에서 Condition Coverage를 만족시키는 통합 케이스를 만들기 위해서는 디시전 #1의 True/False 케이스(각 4개)와 디시전 #2의 케이스(4개)의 조합입니다. 의사 결정 간의 조합은 수영장이 아니라 각 케이스가 한 번만 나타나면 좋기 때문에 마지막으로 케이스의 수는 4개가 됩니다. 의사 결정 # 1 조합 수 A>0 B==0 의사결정 #1 T T T T F T F T T F F F 의사 결정 #2 조합 수 C>0 D==0 의사결정 #2 T T T T F F F T F F F F 의사 결정 #1 x 의사 결정 #2의 통합 케이스 아니 A>0 B==0 C>0 D==0 1 T T T T 2 T F T F 3 F T F T 4 F F F F 이번 경우는 각 의사결정의 관계가 독립적이므로 서로 영업을 받지 못했습니다. 하지만 Nested 구문에서는 이야기가 바뀝니다. if (A>0 || B==0){ // 의사결정 #1 statement1; if (C>0 && D==0){ // 의사결정 #2 statement2; } }   Decision #2는 Decision #1이 True일 때만 True 또는 False로 판단할 수 있습니다. #1이 False이면 #2는 건너뛰므로 판단할 수 없습니다. 앞에서는 정확히 2개의 조건의 결과의 조합을 만들면 좋았지만, 이번은 조합에 제약을 걸어야 한다. 결과는 다음과 같을 것이다. 아니 A>0 B==0 의사결정 #1 C>0 D==0 의사결정 #2 1 T T T T T T 2 T F T T F F 3 F T T F T F 4 F F F Skip Skip - 5 T T T F F F 이 외에도 코드의 조건절간에 제약을 가해야 할 곳이 몇 가지 있습니다. 2 . 거기까지 여기에 기술하지 않습니다.

allpairs.py 라이브러리에는 (당연히) 조합을 제한하는 기능 (필터링)이 있습니다. 샘플 코드는 다음과 같다.
from allpairspy import AllPairs

def is_valid_combination(row):
    """
    This is a filtering function. Filtering functions should return True
    if combination is valid and False otherwise.

    Test row that is passed here can be incomplete.
    To prevent search for unnecessary items filtering function
    is executed with found subset of data to validate it.
    """

    n = len(row)

    if n > 1:
        # Brand Y does not support Windows 98
        if "98" == row[1] and "Brand Y" == row[0]:
            return False

        # Brand X does not work with XP
        if "XP" == row[1] and "Brand X" == row[0]:
            return False

    if n > 4:
        # Contractors are billed in 30 min increments
        if "Contr." == row[3] and row[4] < 30:
            return False

    return True

parameters = [
    ["Brand X", "Brand Y"],
    ["98", "NT", "2000", "XP"],
    ["Internal", "Modem"],
    ["Salaried", "Hourly", "Part-Time", "Contr."],
    [6, 10, 15, 30, 60]
]

print("PAIRWISE:")
for i, pairs in enumerate(AllPairs(parameters, filter_func=is_valid_combination)):
    print("{:2d}: {}".format(i, pairs))

그런데 여기에 논리의 오류가 조금있었습니다. 여기에서 상세하게 언급하지는 않지만, 필터링하는 조건이 복수가 있을 때, 그 순서를 변경하면, 페어링의 결과가 바뀌거나 누락되어 있는 경우가 발생했습니다. 3 여기서 고민은
  • 로직을 직접 수정할 것인가?
  • 로직은 수정하지 않고 필터링 순서를 자동으로 조정하여 결과를 얻는가?

  • 나는 로직을 변경할 자신이 전혀 없었기 때문에 4 두 번째 길을 선택했지만 쉽지 않았습니다. 자동조정도 생각해야 할 경우의 수가 많고, 무려 6개월 가까이의 시간이 걸렸습니다. 그렇다면 allpairs.py에 애증이 생겨 버렸습니다.

    거기서 탄생한 것이 지금은 gitHub에서 전부 삭제했습니다만, TCaseGenerator라고 하는 앱이었습니다. 당시에는 나름대로 MC/DC를 페이크로 구현했습니다. Windows와 MacOS 용 앱을 PyInstaller로 만들고 당시 내 고객에게 다운 받았습니다. 무수한 오류가있는 앱을 ...



    개발을 시작할 때는 Allpairs2.0.1뿐이었습니다. 지금 새롭게 Fork 된 allpairspy2.4.3이 나오고, 이것을 사용하면 됩니다.

    "else if", "nested else if", "컨디션 변수 재사용"등입니다. 어느 쪽이든 어려웠습니다.

    당시에는 allpairs.py를 사용했습니다. 새로 Fork 된 allpairspy.py에서는 아직 테스트하지 않지만 문제 부분의 코드를 그대로보고 싶기 때문에 문제가 여전히 존재할 가능성이 높습니다.

    원인은 알았지만 Side Effect가 매우 무서웠습니다.

    좋은 웹페이지 즐겨찾기