3

私は科学計算コード(C ++で記述)に取り組んでおり、小さなコンポーネントの単体テストを実行することに加えて、「既知の良さ」と比較することによって、数値出力の一部で回帰テストを実行したいと思います。以前のリビジョンからの回答。私が欲しいいくつかの機能があります:

  • 数値を指定された許容誤差と比較できるようにします(丸め誤差と緩い期待の両方)
  • int、doubleなどを区別し、必要に応じてテキストを無視する機能
  • 何がどこで問題が発生したかを示す適切にフォーマットされた出力:データの複数列のテーブルで、異なる列エントリのみを表示します
  • 戻るEXIT_SUCCESSEXIT_FAILURE、ファイルが一致するかどうかに応じて

これを行う優れたスクリプトやアプリケーションはありますか、それとも出力ファイルを読み取って比較するためにPythonで自分自身をロールバックする必要がありますか?確かに、私はこの種の要件を持つ最初の人ではありません。

[以下は厳密には関係ありませんが、何をすべきかの決定に影響を与える可能性があります。私はCMakeとその組み込みCTest機能を使用して、GoogleTestフレームワークを使用する単体テストを実行します。必要な回帰ソフトウェアを呼び出すために、いくつかのadd_custom_commandステートメントを追加するのは難しいことではないと思います。]CMakeLists.txt

4

4 に答える 4

3

PyUnitを選択する必要があります。これは、現在、という名前で標準ライブラリの一部になっていますunittest。それはあなたが求めたすべてをサポートします。許容誤差チェックは、たとえば、で実行されassertAlmostEqual()ます。

于 2009-06-28T18:51:39.677 に答える
0

ndiffユーティリティは、探しているものに近い場合があります。diffに似ていますが、数値のテキストファイルを目的の許容範囲と比較します。

于 2009-07-01T01:33:15.837 に答える
0

結局、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)
于 2009-07-15T18:03:49.053 に答える
0

パーティーにかなり遅れていることは知っていますが、数か月前に、このワークフローを簡単にするためにnrtestユーティリティを作成しました。それもあなたを助けるかもしれないように聞こえます。

ここに簡単な概要があります。各テストは、入力ファイルと予想される出力ファイルによって定義されます。実行後、出力ファイルはポータブルベンチマークディレクトリに保存されます。次に、2番目のステップで、このベンチマークを参照ベンチマークと比較します。最近の更新でユーザー拡張機能が有効になったため、カスタムデータの比較関数を定義できます。

お役に立てば幸いです。

于 2016-03-12T06:26:23.580 に答える