26

Pythonプロジェクトのテストの数と質を改善しようとしています。テストの数が増えるにつれて私が遭遇した困難の1つは、各テストが何をするのか、そしてそれが問題を見つけるのにどのように役立つのかを知ることです。テストを追跡することの一部は、より良い単体テスト名(他の場所で対処されていますであることを知っていますが、ドキュメントと単体テストがどのように連携するかを理解することにも興味があります。

ユニットテストを文書化して、それらのテストが将来失敗した場合の有用性を向上させるにはどうすればよいですか?具体的には、優れた単体テストdocstringを作成するものは何ですか?

説明的な回答と、優れたドキュメントを備えた単体テストの例の両方をいただければ幸いです。私はPythonのみを使用していますが、他の言語からの練習も受け付けています。

4

5 に答える 5

17

私は、メソッド名のみを使用して単体テストについてほとんど文書化します。

testInitializeSetsUpChessBoardCorrectly()
testSuccessfulPromotionAddsCorrectPiece()

私のテストケースのほぼ100%について、これは単体テストが何を検証しているのかを明確に説明しており、それが私が使用するすべてです。ただし、より複雑なテストケースのいくつかでは、メソッド全体にいくつかのコメントを追加して、いくつかの行が何をしているのかを説明します。

プロジェクト内のすべてのテストケースの名前を解析してドキュメントファイルを生成するツール(Ruby用だと思います)を見たことがありますが、名前を思い出せません。チェスクイーンクラスのテストケースがある場合:

testCanMoveStraightUpWhenNotBlocked()
testCanMoveStraightLeftWhenNotBlocked()

このツールは、次のような内容のHTMLドキュメントを生成します。

Queen requirements:
 - can move straight up when not blocked.
 - can move straight left when not blocked.
于 2009-11-13T01:47:04.690 に答える
15

おそらく問題は、テストdocstringを書くのに最適な方法ではなく、テスト自体を書く方法にありますか?自己文書化するような方法でテストをリファクタリングすることは大いに役立つ可能性があり、コードが変更されてもdocstringが古くなることはありません。

テストをより明確にするためにできることがいくつかあります。

  • 明確で説明的な試験方法名(すでに述べた)
  • テスト本体は明確かつ簡潔である必要があります(自己文書化)
  • メソッド内の複雑なセットアップ/ティアダウンなどを抽象化します
  • もっと?

たとえば、次のようなテストがある場合:

def test_widget_run_returns_0():
    widget = Widget(param1, param2, "another param")
    widget.set_option(true)
    widget.set_temp_dir("/tmp/widget_tmp")
    widget.destination_ip = "10.10.10.99"

    return_value = widget.run()

    assert return_value == 0
    assert widget.response == "My expected response"
    assert widget.errors == None

セットアップステートメントをメソッド呼び出しに置き換えることができます。

def test_widget_run_returns_0():
    widget = create_basic_widget()
    return_value = widget.run()
    assert return_value == 0
    assert_basic_widget(widget)

def create_basic_widget():
    widget = Widget(param1, param2, "another param")
    widget.set_option(true)
    widget.set_temp_dir("/tmp/widget_tmp")
    widget.destination_ip = "10.10.10.99"
    return widget

def assert_basic_widget():
    assert widget.response == "My expected response"
    assert widget.errors == None

テストメソッドは、テストに固有のDSLの一種である、意図を明らかにする名前を持つ一連のメソッド呼び出しで構成されていることに注意してください。そのようなテストにはまだドキュメントが必要ですか?

もう1つの注意点は、テストメソッドは主に1つの抽象化レベルにあるということです。テストメソッドを読んでいる人は、アルゴリズムが次のようになっていることを確認できます。

  • ウィジェットの作成
  • ウィジェットで実行を呼び出す
  • コードを主張することは私たちが期待することをしました

テスト方法についての彼らの理解は、ウィジェットの設定の詳細によって混乱することはありません。これは、テスト方法よりも1レベル低い抽象化です。

テストメソッドの最初のバージョンは、インラインセットアップパターンに従います。2番目のバージョンは、作成方法委任されたセットアップのパターンに従います。

コードの「理由」を説明する場合を除いて、一般的にコメントには反対です。ボブ・マーチンおじさんのクリーンコードを読んで、私はこれを確信しました。コメントに関する章とテストに関する章があります。私はそれをお勧めします。

自動テストのベストプラクティスの詳細については、xUnitパターンを確認してください。

于 2009-11-13T02:40:10.160 に答える
4

テストメソッドの名前は、テスト対象を正確に表す必要があります。ドキュメントには、テストが失敗する原因が記載されている必要があります。

于 2009-11-13T02:00:18.103 に答える
0

doc文字列では、説明的なメソッド名とコメントを組み合わせて使用​​する必要があります。これを行う良い方法は、ドキュメント文字列に基本的な手順と検証手順を含めることです。次に、テストの実行と結果の収集を自動化するある種のテストフレームワークからこれらのテストを実行する場合、フレームワークに各テストメソッドのドキュメント文字列の内容とそのstdout+stderrをログに記録させることができます。

基本的な例は次のとおりです。

class SimpelTestCase(unittest.TestCase):
    def testSomething(self):
        """ Procedure:
            1. Print something
            2. Print something else
            ---------
            Verification:
            3. Verify no errors occurred
        """
        print "something"
        print "something else"

テストで手順を実行すると、テストが何をしているのかを理解するのがはるかに簡単になります。また、テスト出力にdocstringを含めると、後で結果を確認するときに何がうまくいかなかったのかを簡単に把握できます。私が以前働いていた場所はこのようなことをしていて、障害が発生したときに非常にうまくいきました。CruiseControlを使用して、チェックインごとに単体テストを自動的に実行しました。

于 2009-11-13T02:35:59.273 に答える
0

テストが失敗すると(合格する前に)、エラーメッセージが表示され、何が起きているかがわかります。それはあなたがそのように計画した場合にのみ起こります。

これは完全に、テストクラス、テストメソッド、およびアサートメッセージの名前の問題です。テストが失敗し、これら3つの手がかりから何が起きているのかわからない場合は、名前を変更するか、テストクラスを分割します。

フィクスチャの名前がClassXTestsで、テストの名前がTestMethodXであり、エラーメッセージが「expectedtrue、returnedfalse」の場合は発生しません。それはずさんなテストライティングの兆候です。

ほとんどの場合、何が起こったのかを知るためにテストやコメントを読む必要はありません。

于 2009-11-13T20:01:28.150 に答える