Drafts

@cm3 の草稿置場 / 少々Wikiっぽく使っているので中身は適宜追記修正されます。

テストコードのパターン(1):変換スクリプトのテストコード

変換スクリプトのテストコードは正しい変換の前後のファイルを置いておいて、現在のコードで変換したものと正解が一致するかをチェックするという形になるだろう。

xlsx2csv/run-windows at 67a648256c54fea54f4abb2d5f4ddefebeb214b7 · cm3/xlsx2csvが正にそういうコードになっている。要素ごとに少し解説する。

バージョンごとのチェック

Windows の方では、PEP 397 に基づいたランチャーが出されていて vinay.sajip / pylauncher / ダウンロード — Bitbucket からインストールすると、C:\Windows\py.exe というのがインストールされる。これで、py -3 py -3.4 py -2.7 みたいな形でバージョンごとの Python を実行できるようになるので便利。

こういうのが LinuxWindows で異なるので初めはテストコードを分けていたが、今では以下のように振り分けを用意することで、スクリプトとしては1つに統一している(xlsx2csv/run at ceb72292a1c0df952fdc512353451c5a018f179a · cm3/xlsx2csv)。

        if os.name == 'posix':# in case of Linux
            left = subprocess.check_output(["python%s" %pyver, "./xlsx2csv.py"] + arguments + ["test/%s.%s" %(case, ext)]).decode('utf-8').replace('\r','')
        elif os.name == 'nt':# in case of Windows
            # Use py.exe http://blog.python.org/2011/07/python-launcher-for-windows_11.html on Windows
            left = subprocess.check_output(["py", "-%s" %pyver, "./xlsx2csv.py"] + arguments + ["test/%s.%s" %(case, ext)]).decode('utf-8').replace('\r','')
        else:
            print("os.name is unexpected: "+os.name)
            sys.exit(1)

参考:

subprocess.check_output

コマンドを実行して返り値を文字列として得る。

left = subprocess.check_output("py -%s ./xlsx2csv.py %s test/%s.%s" %(pyver, arguments, case, ext)).decode('utf-8')

subprocess.check_output のカッコ内に実行コマンドが書いてあって、返ってきた結果を decode('utf-8') として文字列にして正解ファイルと比較している。 これが可能なのは、出力ファイルが指定されなかった場合 sys.stdout に出力するような仕様のプログラムになているから。 但し、一旦 sys.stdout を経由するので、改行コードなどを厳密にチェックすることはできない。 また、変換スクリプトはファイルの出力を行うのだから open 関数を必然的に使うけれども、その部分を検証していないことになる。

そこをきちんとテストしたければ、定型の拡張子でファイルを出力し、.gitignore でリポジトリに含めないようにしておくのがいい。

成功なら成功、異なる場合はその差異を表示

difflibなんかを使ってもいいけれど、今回は

            print("FAILED: %s %s" %(case, pyver))
            print(" actual:", left.replace("\r", "\r").replace("\n", "\n"))
            print(" expected:", right.replace("\r", "\r").replace("\n", "\n"))

とシンプルに書いている。改行コードの違いを気にするスクリプトなので、それが分かり易いようにしている。

あとは個々のファイル名を並べるだけ

上の仕組みを関数化しておいて、それをそれぞれの元ファイル正解ファイルペアについて実行していく。

compare("datetime", "-f "%Y-%m-%d %H:%M:%S"")
compare("empty_row")
compare("junk-small")
compare("last-column-empty")
compare("sheets", "-a")
compare("skip_empty_lines", "-i")
compare("twolettercolumns")
compare("xlsx2csv-test-file")
compare("escape", "-e")
compare("hyperlinks", "--hyperlinks")
compare("hyperlinks_continous", "--hyperlinks")
compare("namespace")
compare("float")