문제

저는 과학적인 컴퓨팅 코드(C++로 작성) 작업을 하고 있으며 더 작은 구성 요소에 대한 단위 테스트를 수행하는 것 외에도 "알려진 양호한" 구성 요소와 비교하여 일부 수치 출력에 대해 회귀 테스트를 수행하고 싶습니다. 이전 개정판의 답변.내가 원하는 몇 가지 기능이 있습니다:

  • 지정된 허용오차에 대한 숫자 비교 허용(반올림 오류 및 느슨한 기대 모두에 대해)
  • int, double 등을 구별하고 필요한 경우 텍스트를 무시하는 기능
  • 무엇이 잘못되었고 어디서 문제가 발생했는지 알려주는 올바른 형식의 출력:다중 열 데이터 테이블에서는 서로 다른 열 항목만 표시합니다.
  • 반품 EXIT_SUCCESS 또는 EXIT_FAILURE 파일이 일치하는지 여부에 따라

이 작업을 수행하는 좋은 스크립트나 응용 프로그램이 있습니까? 아니면 출력 파일을 읽고 비교하기 위해 Python에서 직접 실행해야 합니까?확실히 나는 이런 종류의 요구 사항을 가진 최초의 사람이 아닙니다.

[다음은 엄격하게 관련이 있는 것은 아니지만 무엇을 할지 결정하는 데 영향을 미칠 수 있습니다.저는 CMake와 여기에 포함된 CTest 기능을 사용하여 Google 테스트 프레임워크를 사용하는 단위 테스트를 구동합니다.몇 가지를 추가하는 것이 어렵지 않을 것이라고 생각합니다. add_custom_command 내 진술 CMakeLists.txt 필요한 회귀 소프트웨어를 호출할 수 있습니다.]

도움이 되었습니까?

해결책 3

나는 결국 내가 원하는 것을 어느 정도 수행하기 위해 Python 스크립트를 작성하게 되었습니다.

#!/usr/bin/env python

import sys
import re
from optparse import OptionParser
from math import fabs

splitPattern = re.compile(r',|\s+|;')

class FailObject(object):
    def __init__(self, options):
        self.options = options
        self.failure = False

    def fail(self, brief, full = ""):
        print ">>>> ", brief
        if options.verbose and full != "":
            print "     ", full
        self.failure = True


    def exit(self):
        if (self.failure):
            print "FAILURE"
            sys.exit(1)
        else:
            print "SUCCESS"
            sys.exit(0)

def numSplit(line):
    list = splitPattern.split(line)
    if list[-1] == "":
        del list[-1]

    numList = [float(a) for a in list]
    return numList

def softEquiv(ref, target, tolerance):
    if (fabs(target - ref) <= fabs(ref) * tolerance):
        return True

    #if the reference number is zero, allow tolerance
    if (ref == 0.0):
        return (fabs(target) <= tolerance)

    #if reference is non-zero and it failed the first test
    return False

def compareStrings(f, options, expLine, actLine, lineNum):
    ### check that they're a bunch of numbers
    try:
        exp = numSplit(expLine)
        act = numSplit(actLine)
    except ValueError, e:
#        print "It looks like line %d is made of strings (exp=%s, act=%s)." \
#                % (lineNum, expLine, actLine)
        if (expLine != actLine and options.checkText):
            f.fail( "Text did not match in line %d" % lineNum )
        return

    ### check the ranges
    if len(exp) != len(act):
        f.fail( "Wrong number of columns in line %d" % lineNum )
        return

    ### soft equiv on each value
    for col in range(0, len(exp)):
        expVal = exp[col]
        actVal = act[col]
        if not softEquiv(expVal, actVal, options.tol):
            f.fail( "Non-equivalence in line %d, column %d" 
                    % (lineNum, col) )
    return

def run(expectedFileName, actualFileName, options):
    # message reporter
    f = FailObject(options)

    expected  = open(expectedFileName)
    actual    = open(actualFileName)
    lineNum   = 0

    while True:
        lineNum += 1
        expLine = expected.readline().rstrip()
        actLine = actual.readline().rstrip()

        ## check that the files haven't ended,
        #  or that they ended at the same time
        if expLine == "":
            if actLine != "":
                f.fail("Tested file ended too late.")
            break
        if actLine == "":
            f.fail("Tested file ended too early.")
            break

        compareStrings(f, options, expLine, actLine, lineNum)

        #print "%3d: %s|%s" % (lineNum, expLine[0:10], actLine[0:10])

    f.exit()

################################################################################
if __name__ == '__main__':
    parser = OptionParser(usage = "%prog [options] ExpectedFile NewFile")
    parser.add_option("-q", "--quiet",
                      action="store_false", dest="verbose", default=True,
                      help="Don't print status messages to stdout")

    parser.add_option("--check-text",
                      action="store_true", dest="checkText", default=False,
                      help="Verify that lines of text match exactly")

    parser.add_option("-t", "--tolerance",
                      action="store", type="float", dest="tol", default=1.e-15,
                      help="Relative error when comparing doubles")

    (options, args) = parser.parse_args()

    if len(args) != 2:
        print "Usage: numdiff.py EXPECTED ACTUAL"
        sys.exit(1)

    run(args[0], args[1], options)

다른 팁

당신은 가야한다 PyUnit, 이제 이름 아래 표준 lib의 일부입니다. unittest.귀하가 요청한 모든 것을 지원합니다.예를 들어 공차 검사는 다음과 같이 수행됩니다. assertAlmostEqual().

그만큼 ndiff 유틸리티는 당신이 찾고 있는 것과 비슷할 수 있습니다:diff와 비슷하지만 숫자의 텍스트 파일을 원하는 허용오차와 비교합니다.

파티에 꽤 늦었다는 건 알지만 몇 달 전에 나는 다음과 같은 글을 썼다. nrtest 이 작업 흐름을 더 쉽게 만들기 위한 유틸리티입니다.당신에게도 도움이 될 것 같습니다.

다음은 간단한 개요입니다.각 테스트는 입력 파일과 예상 출력 파일로 정의됩니다.실행 후 출력 파일은 휴대용 벤치마크 디렉터리에 저장됩니다.그런 다음 두 번째 단계에서는 이 벤치마크를 참조 벤치마크와 비교합니다.최근 업데이트를 통해 사용자 확장 기능이 활성화되었으므로 사용자 정의 데이터에 대한 비교 기능을 정의할 수 있습니다.

도움이 되었으면 좋겠습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top