1

バックグラウンド

複数の入力値に対して単一の単体テストを実行し、失敗を表示する方法を見つけようとしています。これは、私が考えていることの簡単なデモです。

from time import time
import unittest

def demo():
    while True:
        count = 0
        for i in xrange(10):
            count += 1
            yield int(time() * 1000) + count
        count = 0

class TestDemo(unittest.TestCase):
    def setUp(self):
        self.gen = demo()
        self.prev = next(self.gen)

    def test_always_bigger(self):
        for cycle in xrange(1000):
            curr = next(self.gen)
            self.assertGreater(curr, self.prev)
            self.prev = curr

if __name__ == '__main__':
    unittest.main()

私が見つけた最も類似した質問は、ある種の動的test_<something>メソッド作成 (例: 123 ) またはノーズ ジェネレータ(例: 12 ) で回答されています。標準ライブラリに固執しながら、予測不可能な入力に基づいて何千もの反復を実行しようとしているため、どちらのソリューションも最適ではありません。単純なループ (上に示したように) は 2 つの制限がありますがうまく機能します。そして、メソッド内の 1 つの失敗test_<...>がテスト全体に失敗します。

質問

私は初期の失敗に耐えることができますが、成功時に何千行もの出力を作成せずに、失敗を引き起こす入力に到達するにはどうすればよいでしょうか?

無回答

assert...メソッドkwargを試してみmsgましたが、実際には、ライブラリが既に適切に処理しているような些細なケースでのみうまく機能します。上記の例では、unittestlongは、アサーションの失敗の原因となった 2 つの を表示することを知っています。これに注釈を付けて、`self.assertGreater(curr, self.prev, msg="cycle %s" % cycle) で失敗について多くの洞察を提供できますが、assertDictEquals で深くネストされた dict を表示するのは面倒です。

望ましい解決策

この回答は logging モジュールの興味深い使用法を示していますが、成功したテストごとに数千行の出力が生成されます。テストメソッド内から障害を検出することは可能ですか? 何かのようなもの:

    def test_always_bigger(self):
        for cycle in xrange(1000):
            curr = next(self.gen)
            fail = self.assertGreater(curr, self.prev)
            if fail:
                log.debug('...')
            self.prev = curr
4

1 に答える 1

2
def test_always_bigger(self):
    for cycle in xrange(1000):
        curr = next(self.gen)
        try:
            self.assertGreater(curr, self.prev)
        except AssertionError: # raised by TestCase.fail, called by all asserts
            log.debug('...')
            raise
        self.prev = curr

これは、失敗した場合のロギングのセマンティクスを実装し、失敗を続行します。すべてのテストを終了したい場合は、次のようにします。

def test_always_bigger(self):
    ex = None
    for cycle in xrange(1000):
        curr = next(self.gen)
        try:
            self.assertGreater(curr, self.prev)
        except AssertionError, ae:
            ex = ae # just remember it
            log.debug('...')
        self.prev = curr
    if ex:
        raise ex

明らかに、これは最初の のみをAssertionError発生させますが、完了するまで実行され、すべての失敗を個別にログに記録します。この関数はフレームワークの 1 つのテストのみを表しているため、複数の失敗を実際に生成することはできません。

何らかの理由ですべての例外にアクセスする必要がある場合は、次の方法で回避できる場合があります (完全にテストされていませんunittest) 。

def test_always_bigger(self):
    exes = []
    for cycle in xrange(1000):
        curr = next(self.gen)
        try:
            self.assertGreater(curr, self.prev)
        except AssertionError, ae:
            exes.append(ae)
            log.debug('...')
        self.prev = curr
    if exes:
        self.fail(exes)
        # if that doesn't work, try: raise AssertionError(exes)
于 2012-05-03T04:17:22.837 に答える