8

私はPythonモジュールを書いていますが、それを単体テストしたいと思います。私はPythonを初めて使用し、利用可能なオプションに多少戸惑っています。

現在、命令型ではなく宣言型が好きなので、テストをdoctestとして書きたいと思います(ただし、誤った情報があった場合は、この設定を無視してください)。ただし、これにはいくつかの疑問があります。

  1. テストはどこに置くべきですか?彼らがテストしているコードと同じファイル(またはdoctestsの場合はdocstrings)?それとも、それらを独自のディレクトリに分離する方がよいと考えられますか?
  2. モジュール全体のすべてのテストをコマンドラインから一度に実行するにはどうすればよいですか?
  3. テストスイートのコードカバレッジを報告するにはどうすればよいですか?
  4. Pythonでのユニットテストについて知っておくべき他のベストプラクティスはありますか?
4

6 に答える 6

12

それが誤った情報を与えられた場合、この好みについて私を非難してください

私は、少なくとも1つのプロジェクト内で、他のどのオープンソース開発者よりもdoctest広範囲に(使用目的の境界を広げる方法で)使用したと思います。私のgmpyプロジェクトのすべてのテストはdoctestです。それは始めたときは真新しいものでした、それは素晴らしい小さなトリックのようでした、そして何かをする価値があるならそれは過剰に行う価値があります-そうですか?-)gmpy

間違い。すべてを適切な単体テストとしてやり直すのは手間がかかりすぎることを除いてgmpy、私はその間違いを二度と犯しませんでした。最近では、単体テストを単体テストとして使用し、ドキュメントをチェックするためだけにドキュメントテストを使用しています。使用することを意図しました。doctestが行うこと(期待と平等の実際の結果を比較する-それだけです)は、堅実なテストスイートを構築するための良いまたは健全な基盤ではありません。それ以外の意図はありませんでした。

を見てみることをお勧めします。unittest新しいPython2.7のモジュールは、はるかに豊富で優れています。2.4、2.5、または2.6に固執している場合でも、ダウンロードしてインストールできるunittest2で新機能を使用できます。非常によくnose補完します。unittest

ユニットテストに耐えられない場合(ただし、試してみると、成長します!-)、まったく異なる哲学を持つ代替パッケージであるpy.testを試してみてください。

ただし、ドキュメントの例以外のものをテストするためにストレッチしないでください!doctest正確な等式の比較は、私が(比喩的な;-)の費用で学ばなければならなかったので、あまりにも頻繁にあなたの邪魔になりますgmpy...

于 2010-07-14T02:15:19.790 に答える
3

私はこれらの理由でdoctestsが好きではありません:

  • テストのサブセットを実行することはできません。テストが失敗した場合は、1つのテストだけを実行すると便利です。Doctestはそれを行う方法を提供していません。
  • doctestの途中で失敗が発生した場合、すべてが停止します。破損に対処する方法を決定するために、すべての結果を確認したいと思います。
  • コーディングスタイルは定型化されており、印刷可能な結果が必要です。
  • コードは特別な方法で実行されるため、実行方法を推測するのが難しく、ヘルパーを追加するのが難しく、テストをプログラムするのが難しくなります。

このリストは、私のブログ投稿「doctestについて私が気に入らないこと」から抜粋したものです。ここには、さらに多くの点があり、要点を議論する長いコメントがあります。

カバレッジについて:Doctest内のカバレッジを測定するPython用のカバレッジツールはないと思います。しかし、それらは分岐やループのないステートメントの単なる長いリストなので、それは問題ですか?

于 2010-07-14T02:25:35.220 に答える
2

私は、アレックスがプログラマーのカーブで私よりかなり先を行っているのではないかと疑っていますが、Pythonの経験がある人(専門家や伝道者ではなく「ユーザー」として)の視点が必要な場合は、同じではありませんリーグでは、ユニットテストに関する私の調査結果はほとんど同じです。

Doctestsは、最初は簡単なテストには最適に聞こえるかもしれませんが、他の場所で推奨されていたため、自宅での個人的なプロジェクトにその方向に進みました。職場では鼻を使っており(缶詰になって包み込んでいたのですが、少し前までpyUnitを使っていたような印象を受けました)、数か月前に自宅でも鼻に移動しました。

初期セットアップ時間と管理オーバーヘッド、および実際のコードからの分離は、特にコードベースがそれほど大きくないものをテストしている場合は、最初は不要に思えるかもしれませんが、長期的には、doctestsが私がやりたかったすべてのリファクタリングまたは再構築の方法で、維持するのはかなり難しく、拡張することは事実上不可能であり、初期の節約を非常に迅速に相殺しました。はい、ユニットテストは統合テストと同じではないことは承知していますが、doctestはユニットを厳密に定義する傾向があります。また、有効なスケッチツールまたは開発モデルであると判断した場合は、ユニットベースのアジャイルにはあま​​り適していません。

pyUnitまたはnoseがあなたを導く方法を計画してから、ユニットテストを改良するのに少し時間がかかるかもしれませんが、短期的にも、実際に多くのレベルで役立つことがわかる可能性があります。私はそれが私のために行われたことを知っています、そして私は私が最近取り組んでいるコードベースの複雑さと規模に比較的慣れていません。最初の数週間は歯を食いしばってください。

于 2010-07-14T05:36:46.810 に答える
1

カバレッジについては、優れたcoverage.pyを確認してください。

そうでなければ、アレックス・マルテッリが書いたすべてが非常に的を射ている。

于 2010-07-14T02:26:11.963 に答える
1

doctestは、問題のオブジェクトの基本的な使用法のいくつかを説明する、迅速でマイナーな単体テストに最適です(docstringに表示されるため、help(何でも)など)。

個人的には、unittestモジュールを使用すると、広範囲でより徹底的なテストがより効果的であることがわかりました。現在、2.7モジュール(unittest2にバックポートされています)には、さらに便利なアサーションがあります。単体テストフレームワークを使用して、テストスイートをセットアップし、必要に応じて複雑なシナリオを設定して、さまざまなテストの全範囲を一度にカバーできます(コマンドラインごと)。

Ned Batchelderによるcoverage.pyは、@ bstpierreが言及しているように、これらのいずれでも機能します。コードのテスト済みのものとそうでないものを確認するために、これをお勧めします。これをCIシステム(つまり、Hudsonまたは使用したいもの)に追加して、カバーされているものとカバーされていないものを把握できます。HTMLレポートは、テストカバレッジでヒットしていないものを確認するのに最適です。CoverageはJunitxml出力をサポートします。これは、多くのCIシステムが、チャート化された進行中の結果を提供して、ビルドが時間の経過とともに良くなったり悪くなったりするのを確認する方法を知っています。

于 2010-07-14T02:31:29.223 に答える
0

私は、スケーリングではなくdoctestについて提起された上記のすべての点に同意し、unittestに固執することを好みます。

私が貢献できるヒントの1つは、コード処理から単体テストを呼び出すこと__name__ == "__main__です。これにより、テストファイルをスクリプトとして実行すると、テストが実行されます。

例えば:

#!/usr/bin/env python

"""
Unit tests for the GetFiles.py utility
"""

import unittest
from FileUtilities import getTree

class TestFileUtilities(unittest.TestCase):

   def testGetTree(self):
      """
      Tests that a known tree is found and incidentally confirms
      that we have the tree we expected to use for our current
      sample extraction.
      """
      found = getTree('./anzmeta-dtd', '.pen')
      expected_path_tail = ['ISOdia.pen',
                       'ISOgrk1.pen',
                       'ISOtech.pen']
      for i, full_path in enumerate(found):
         assert full_path.endswith( expected_path_tail[i] ), expected_path_tail[i]

# other tests elided         

if __name__ == "__main__":
   # When this module is executed from the command-line, run all its tests
   unittest.main()
于 2010-07-14T08:49:10.410 に答える