アサーションが失敗したときにPythonのユニットテストを続行する


84

編集:より良い例に切り替え、これが本当の問題である理由を明らかにしました。

1回のテストで複数の失敗を確認できるように、アサーションが失敗しても実行を継続する単体テストをPythonで記述したいと思います。例えば:

class Car(object):
  def __init__(self, make, model):
    self.make = make
    self.model = make  # Copy and paste error: should be model.
    self.has_seats = True
    self.wheel_count = 3  # Typo: should be 4.

class CarTest(unittest.TestCase):
  def test_init(self):
    make = "Ford"
    model = "Model T"
    car = Car(make=make, model=model)
    self.assertEqual(car.make, make)
    self.assertEqual(car.model, model)  # Failure!
    self.assertTrue(car.has_seats)
    self.assertEqual(car.wheel_count, 4)  # Failure!

ここで、テストの目的は、Car's__init__がフィールドを正しく設定していることを確認することです。私はそれを4つのメソッドに分割することができます(そしてそれはしばしば素晴らしいアイデアです)が、この場合、単一の概念をテストする単一のメソッドとして保持する方が読みやすいと思います(「オブジェクトは正しく初期化されます」)。

ここでメソッドを分割しないことが最善であると仮定すると、新しい問題が発生します。すべてのエラーを一度に確認することはできません。modelエラーを修正してテストを再実行すると、wheel_countエラーが表示されます。最初にテストを実行したときに両方のエラーを確認する時間を節約できます。

比較のために、GoogleのC ++ユニットテストフレームワークは、致命的でないEXPECT_*アサーションと致命的なアサーションを区別しますASSERT_*

アサーションはペアで提供され、同じことをテストしますが、現在の機能に異なる影響を及ぼします。ASSERT_ *バージョンは、失敗すると致命的な失敗を生成し、現在の機能を中止します。EXPECT_ *バージョンは致命的ではない障害を生成し、現在の機能を中止しません。通常、EXPECT_ *が推奨されます。これは、テストで複数の障害を報告できるためです。ただし、問題のアサーションが失敗したときに続行しても意味がない場合は、ASSERT_ *を使用する必要があります。

EXPECT_*Pythonで同様の動作を取得する方法はありunittestますか?にない場合unittest、この動作をサポートする別のPythonユニットテストフレームワークはありますか?


ちなみに、致命的ではないアサーションから実際のテストがいくつ役立つか知りたいので、いくつかのコード例を調べました(Google Code Search、RIPの代わりにsearchcodeを使用するように2014-08-19を編集)。最初のページからランダムに選択された10個の結果のうち、すべてに同じテスト方法で複数の独立したアサーションを作成したテストが含まれていました。すべての人が致命的ではない主張から利益を得るでしょう。


2
どうしたの?私はこのトピックに興味があり(コメントよりも広い場所で話し合うことができるまったく異なる理由で)、あなたの経験を知りたいと思います。ちなみに、「コード例」のリンクは「残念ながら、このサービスはシャットダウンされました」という結果になるので、キャッシュされたバージョンがある場合は、それも見てみたいと思います。
ダビデ

将来の参考のために、これは現在のシステムでの同等の検索であると思いますが、結果は上記のとおりではなくなりました。
ZAD-Man 2014

2
@デイヴィッド、私は何もしなかった。「メソッドごとに1つのアサーションのみを作成する」アプローチは、私には厳密に独断的すぎるように見えますが、実行可能な(そして保守可能な)唯一の解決策は、Anthonyの「キャッチアンドアペンド」提案のようです。しかし、それは私にはあまりにも醜いので、メソッドごとに複数のアサーションに固執し、すべての失敗を見つけるために必要以上にテストを実行する必要があります。
ブルースクリステンセン

PyTestと呼ばれるPythonテストフレームワークは非常に直感的であり、デフォルトではすべてのアサートの失敗が表示されます。これは、直面している問題の回避策になる可能性があります。
Surya Shekhar Chakraborty 2018

回答:


9

unittest.TestCaseアサーションが失敗したときにスローするクラスであるため、おそらく実行したいのは派生です。TestCaseスローしないように再設計する必要があります(代わりに失敗のリストを保持する可能性があります)。ものを再構築すると、解決しなければならない他の問題が発生する可能性があります。たとえばTestSuite、に加えられた変更をサポートするために変更を加えるために派生する必要がある場合がありますTestCase


1
これがおそらく最終的な答えになるだろうと思いましたが、私は自分の基地をカバーして、何かが足りないかどうかを確認したかったのです。ありがとう!
ブルースクリステンセン

4
TestCaseソフトアサーションを実装するためにオーバーライドするのはやり過ぎだと思います-それらはPythonで特に簡単に作成できます:すべてAssertionErrorのを(おそらく単純なループで)キャッチし、リストまたはセットに格納するだけです、次にそれらすべてを一度に失敗させます。詳細については、@ AnthonyBatchelorの回答を確認してください。
dcsordas 2013年

2
@dscordasこれが1回限りのテスト用か、ほとんどのテストでこの機能が必要かによって異なります。
Dietbuddha 2013年

43

致命的でないアサーションを作成する別の方法は、アサーション例外をキャプチャして、例外をリストに格納することです。次に、tearDownの一部としてそのリストが空であることを表明します。

import unittest

class Car(object):
  def __init__(self, make, model):
    self.make = make
    self.model = make  # Copy and paste error: should be model.
    self.has_seats = True
    self.wheel_count = 3  # Typo: should be 4.

class CarTest(unittest.TestCase):
  def setUp(self):
    self.verificationErrors = []

  def tearDown(self):
    self.assertEqual([], self.verificationErrors)

  def test_init(self):
    make = "Ford"
    model = "Model T"
    car = Car(make=make, model=model)
    try: self.assertEqual(car.make, make)
    except AssertionError, e: self.verificationErrors.append(str(e))
    try: self.assertEqual(car.model, model)  # Failure!
    except AssertionError, e: self.verificationErrors.append(str(e))
    try: self.assertTrue(car.has_seats)
    except AssertionError, e: self.verificationErrors.append(str(e))
    try: self.assertEqual(car.wheel_count, 4)  # Failure!
    except AssertionError, e: self.verificationErrors.append(str(e))

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

2
私はあなたに同意します。これが、SeleniumがPythonバックエンドの検証エラーを処理する方法です。
アンソニーバチェラー2011

ええ、このソリューションの問題は、すべてのアサートが(失敗者ではなく)エラーとしてカウントされ、エラーをレンダリングする方法が実際には使用できないことです。とにかく方法であり、レンダリング機能は簡単に改善できます
eMarine

私はこのソリューションをdietbuddaの回答と組み合わせてunittest.TestCase、try / exceptブロックですべてのアサーションをオーバーライドすることで使用しています。
thodic 2015年

複雑なテストパターンの場合、これは単体テストエラーを克服するための最良の解決策ですが、すべての試行/例外でテストがかなり醜く見えます。これは、多くのテストと複雑な単一のテストの間のトレードオフです。代わりにエラー辞書を返し始めました。したがって、1つのテストでテストパターン全体をテストし、仲間のカジュアルなPython開発者が読みやすくすることができます。
MortenB

これは非常に賢いので、あなたに嫌気がさします。
courtsimas 2018年

30

1つのオプションは、すべての値をタプルとして一度にアサートすることです。

例えば:

class CarTest(unittest.TestCase):
  def test_init(self):
    make = "Ford"
    model = "Model T"
    car = Car(make=make, model=model)
    self.assertEqual(
            (car.make, car.model, car.has_seats, car.wheel_count),
            (make, model, True, 4))

このテストの出力は次のようになります。

======================================================================
FAIL: test_init (test.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\temp\py_mult_assert\test.py", line 17, in test_init
    (make, model, True, 4))
AssertionError: Tuples differ: ('Ford', 'Ford', True, 3) != ('Ford', 'Model T', True, 4)

First differing element 1:
Ford
Model T

- ('Ford', 'Ford', True, 3)
?           ^ -          ^

+ ('Ford', 'Model T', True, 4)
?           ^  ++++         ^

これは、モデルとホイール数の両方が正しくないことを示しています。


これは賢いです。私がこれまでに見つけた最良の解決策。
Chen Ni

7

単一の単体テストで複数のアサーションを持つことは、アンチパターンと見なされます。単一の単体テストでは、1つのことだけをテストすることが期待されています。おそらく、テストが多すぎます。このテストを複数のテストに分割することを検討してください。このようにして、各テストに適切な名前を付けることができます。

ただし、複数の項目を同時にチェックしても問題ない場合もあります。たとえば、同じオブジェクトのプロパティをアサートする場合です。その場合、実際には、そのオブジェクトが正しいかどうかを主張しています。これを行う方法は、そのオブジェクトでアサートする方法を知っているカスタムヘルパーメソッドを作成することです。このメソッドは、失敗したすべてのプロパティを表示したり、たとえば、アサートが失敗したときに予期されるオブジェクトの完全な状態と実際のオブジェクトの完全な状態を表示するように記述できます。


1
@Bruce:アサーションは失敗または成功するはずです。間に何かがあることはありません。テストは、信頼でき、読みやすく、保守しやすいものでなければなりません。テストに失敗しないアサーションの失敗は悪い考えです。これにより、テストが非常に複雑になり(読みやすさと保守性が低下します)、「失敗が許可される」テストがあると、無視しやすくなります。つまり、信頼性が低くなります。
スティーブン

8
残りのテストを実行できず、それでも致命的である理由。発生する可能性のあるすべての障害を集約するために、障害の再発をどこかで遅らせることができると思います。
Dietbuddha 2011年

5
私たちは両方とも同じことを言っていると思います。失敗するすべてのアサーションでテストが失敗するようにします。@dietbuddhaが述べたように、アサーションがテストされた直後ではなく、テストメソッドが戻ったときに失敗が発生するようにしたいだけです。これにより、メソッド内のすべてのアサートをテストできるため、すべての失敗を1回のショットで確認(および修正)できます。テストは依然として信頼でき、読みやすく、保守可能です(実際にはさらにそうです)。
ブルースクリステンセン

10
彼は、アサーションをヒットしたときにテストが失敗してはならないと言っているのではなく、失敗しても他のチェックが妨げられてはならないと言っています。たとえば、現在、特定のディレクトリがユーザー、グループ、およびその他の書き込み可能であることをテストしています。それぞれが個別のアサーションです。テスト出力から3つのケースすべてが失敗していることを知っておくと便利なので、「Path is not user-writable」を取得するのではなく、1回のchmod呼び出しで修正でき、「Pathis」を取得するためにテストを再実行する必要があります。グループ書き込み不可」など。私が推測するが、私はちょうど彼らが独立したテストであることを主張した...
ティム・キーティング

8
ライブラリがunittestと呼ばれているからといって、テストが分離された単体テストであるとは限りません。unittestモジュールは、pytestやnoseなどと同様に、システムテスト、統合テストなどに最適です。1つの注意点として、失敗するのは1回だけです。本当に迷惑です。すべてのassert関数に、失敗を続行できるようにするパラメーターを追加するか、expectBlahと呼ばれるそのようなことを行うassert関数の複製を追加してもらいたいと思います。そうすれば、unittestを使用してより大きな機能テストを作成する方がはるかに簡単です。
オッケン2014

7

Python 3.4以降、サブテストも使用できます

def test_init(self):
    make = "Ford"
    model = "Model T"
    car = Car(make=make, model=model)
    with self.subTest(msg='Car.make check'):
        self.assertEqual(car.make, make)
    with self.subTest(msg='Car.model check'):
        self.assertEqual(car.model, model)
    with self.subTest(msg='Car.has_seats check'):
        self.assertTrue(car.has_seats)
    with self.subTest(msg='Car.wheel_count check'):
        self.assertEqual(car.wheel_count, 4)

msgパラメーターは、失敗したテストをより簡単に判別するために使用されます。)

出力:

======================================================================
FAIL: test_init (__main__.CarTest) [Car.model check]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 23, in test_init
    self.assertEqual(car.model, model)
AssertionError: 'Ford' != 'Model T'
- Ford
+ Model T


======================================================================
FAIL: test_init (__main__.CarTest) [Car.wheel_count check]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 27, in test_init
    self.assertEqual(car.wheel_count, 4)
AssertionError: 3 != 4

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=2)

1
これは、既存のコードにドロップするのが最も簡単なものとして受け入れられた答えになるはずです。
マイケルスコットカスバート

5

それぞれのアサートを別々の方法で実行します。

class MathTest(unittest.TestCase):
  def test_addition1(self):
    self.assertEqual(1 + 0, 1)

  def test_addition2(self):
    self.assertEqual(1 + 1, 3)

  def test_addition3(self):
    self.assertEqual(1 + (-1), 0)

  def test_addition4(self):
    self.assertEqaul(-1 + (-1), -1)

5
それが1つの可能な解決策であることを私は理解していますが、それは常に実用的であるとは限りません。以前はまとまりのあるテストをいくつかの小さな方法に分割せずに機能するものを探しています。
ブルースクリステンセン

@ブルースクリステンセン:彼らがとてもまとまりがあるなら、おそらく彼らは物語を形成しますか?そして、それらをdoctestにすることができます。これは、失敗した後も実際継続されます。
Lennart Regebro 2011年

1
次のような一連のテストがあります。1。データのロード、2。データのロードのアサート、3。データの変更、4。変更のアサート、5。変更されたデータの保存、6。データの正しく保存のアサート。この方法でどうすればよいですか?これはsetup()テストの1つであるため、にデータをロードすることは意味がありません。しかし、各アサーションを独自の関数に入れると、データを3回ロードする必要があり、それはリソースの膨大な浪費になります。そのような状況に対処するための最良の方法は何ですか?
naught101 2015年

ええと、特定のシーケンスをテストするテストは同じテスト方法でなければなりません。
Lennart Regebro 2015年

4

PyPIにはsoftest、要件を処理するというソフトアサーションパッケージがあります。これは、障害を収集し、例外とスタックトレースのデータを組み合わせて、通常のunittest出力の一部としてすべてを報告することで機能します。

たとえば、次のコードは次のとおりです。

import softest

class ExampleTest(softest.TestCase):
    def test_example(self):
        # be sure to pass the assert method object, not a call to it
        self.soft_assert(self.assertEqual, 'Worf', 'wharf', 'Klingon is not ship receptacle')
        # self.soft_assert(self.assertEqual('Worf', 'wharf', 'Klingon is not ship receptacle')) # will not work as desired
        self.soft_assert(self.assertTrue, True)
        self.soft_assert(self.assertTrue, False)

        self.assert_all()

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

...このコンソール出力を生成します:

======================================================================
FAIL: "test_example" (ExampleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\...\softest_test.py", line 14, in test_example
    self.assert_all()
  File "C:\...\softest\case.py", line 138, in assert_all
    self.fail(''.join(failure_output))
AssertionError: ++++ soft assert failure details follow below ++++

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The following 2 failures were found in "test_example" (ExampleTest):
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Failure 1 ("test_example" method)
+--------------------------------------------------------------------+
Traceback (most recent call last):
  File "C:\...\softest_test.py", line 10, in test_example
    self.soft_assert(self.assertEqual, 'Worf', 'wharf', 'Klingon is not ship receptacle')
  File "C:\...\softest\case.py", line 84, in soft_assert
    assert_method(*arguments, **keywords)
  File "C:\...\Python\Python36-32\lib\unittest\case.py", line 829, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\...\Python\Python36-32\lib\unittest\case.py", line 1203, in assertMultiLineEqual
    self.fail(self._formatMessage(msg, standardMsg))
  File "C:\...\Python\Python36-32\lib\unittest\case.py", line 670, in fail
    raise self.failureException(msg)
AssertionError: 'Worf' != 'wharf'
- Worf
+ wharf
 : Klingon is not ship receptacle

+--------------------------------------------------------------------+
Failure 2 ("test_example" method)
+--------------------------------------------------------------------+
Traceback (most recent call last):
  File "C:\...\softest_test.py", line 12, in test_example
    self.soft_assert(self.assertTrue, False)
  File "C:\...\softest\case.py", line 84, in soft_assert
    assert_method(*arguments, **keywords)
  File "C:\...\Python\Python36-32\lib\unittest\case.py", line 682, in assertTrue
    raise self.failureException(msg)
AssertionError: False is not true


----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

:私はを作成して維持していsoftestます。


3

期待はgtestで非常に便利です。これは要点のPythonの方法であり、コードは次のとおりです。

import sys
import unittest


class TestCase(unittest.TestCase):
    def run(self, result=None):
        if result is None:
            self.result = self.defaultTestResult()
        else:
            self.result = result

        return unittest.TestCase.run(self, result)

    def expect(self, val, msg=None):
        '''
        Like TestCase.assert_, but doesn't halt the test.
        '''
        try:
            self.assert_(val, msg)
        except:
            self.result.addFailure(self, sys.exc_info())

    def expectEqual(self, first, second, msg=None):
        try:
            self.failUnlessEqual(first, second, msg)
        except:
            self.result.addFailure(self, sys.exc_info())

    expect_equal = expectEqual

    assert_equal = unittest.TestCase.assertEqual
    assert_raises = unittest.TestCase.assertRaises


test_main = unittest.main

2

AssertionError例外をキャプチャするための@ Anthony-Batchelorによるアプローチが気に入りました。ただし、デコレータを使用したこのアプローチのわずかなバリエーションであり、テストケースを合格/不合格で報告する方法でもあります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unittest

class UTReporter(object):
    '''
    The UT Report class keeps track of tests cases
    that have been executed.
    '''
    def __init__(self):
        self.testcases = []
        print "init called"

    def add_testcase(self, testcase):
        self.testcases.append(testcase)

    def display_report(self):
        for tc in self.testcases:
            msg = "=============================" + "\n" + \
                "Name: " + tc['name'] + "\n" + \
                "Description: " + str(tc['description']) + "\n" + \
                "Status: " + tc['status'] + "\n"
            print msg

reporter = UTReporter()

def assert_capture(*args, **kwargs):
    '''
    The Decorator defines the override behavior.
    unit test functions decorated with this decorator, will ignore
    the Unittest AssertionError. Instead they will log the test case
    to the UTReporter.
    '''
    def assert_decorator(func):
        def inner(*args, **kwargs):
            tc = {}
            tc['name'] = func.__name__
            tc['description'] = func.__doc__
            try:
                func(*args, **kwargs)
                tc['status'] = 'pass'
            except AssertionError:
                tc['status'] = 'fail'
            reporter.add_testcase(tc)
        return inner
    return assert_decorator



class DecorateUt(unittest.TestCase):

    @assert_capture()
    def test_basic(self):
        x = 5
        self.assertEqual(x, 4)

    @assert_capture()
    def test_basic_2(self):
        x = 4
        self.assertEqual(x, 4)

def main():
    #unittest.main()
    suite = unittest.TestLoader().loadTestsFromTestCase(DecorateUt)
    unittest.TextTestRunner(verbosity=2).run(suite)

    reporter.display_report()


if __name__ == '__main__':
    main()

コンソールからの出力:

(awsenv)$ ./decorators.py 
init called
test_basic (__main__.DecorateUt) ... ok
test_basic_2 (__main__.DecorateUt) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
=============================
Name: test_basic
Description: None
Status: fail

=============================
Name: test_basic_2
Description: None
Status: pass

1

@Anthony Batchelorからの回答に問題がありました。これはtry...catch、単体テスト内での使用を余儀なくされたためです。代わりtry...catchに、TestCase.assertEqualメソッドのオーバーライドでロジックをカプセル化しました。コードは次のとおりです。

import unittest
import traceback

class AssertionErrorData(object):

    def __init__(self, stacktrace, message):
        super(AssertionErrorData, self).__init__()
        self.stacktrace = stacktrace
        self.message = message

class MultipleAssertionFailures(unittest.TestCase):

    def __init__(self, *args, **kwargs):
        self.verificationErrors = []
        super(MultipleAssertionFailures, self).__init__( *args, **kwargs )

    def tearDown(self):
        super(MultipleAssertionFailures, self).tearDown()

        if self.verificationErrors:
            index = 0
            errors = []

            for error in self.verificationErrors:
                index += 1
                errors.append( "%s\nAssertionError %s: %s" % ( 
                        error.stacktrace, index, error.message ) )

            self.fail( '\n\n' + "\n".join( errors ) )
            self.verificationErrors.clear()

    def assertEqual(self, goal, results, msg=None):

        try:
            super( MultipleAssertionFailures, self ).assertEqual( goal, results, msg )

        except unittest.TestCase.failureException as error:
            goodtraces = self._goodStackTraces()
            self.verificationErrors.append( 
                    AssertionErrorData( "\n".join( goodtraces[:-2] ), error ) )

    def _goodStackTraces(self):
        """
            Get only the relevant part of stacktrace.
        """
        stop = False
        found = False
        goodtraces = []

        # stacktrace = traceback.format_exc()
        # stacktrace = traceback.format_stack()
        stacktrace = traceback.extract_stack()

        # /programming/54499367/how-to-correctly-override-testcase
        for stack in stacktrace:
            filename = stack.filename

            if found and not stop and \
                    not filename.find( 'lib' ) < filename.find( 'unittest' ):
                stop = True

            if not found and filename.find( 'lib' ) < filename.find( 'unittest' ):
                found = True

            if stop and found:
                stackline = '  File "%s", line %s, in %s\n    %s' % ( 
                        stack.filename, stack.lineno, stack.name, stack.line )
                goodtraces.append( stackline )

        return goodtraces

# class DummyTestCase(unittest.TestCase):
class DummyTestCase(MultipleAssertionFailures):

    def setUp(self):
        self.maxDiff = None
        super(DummyTestCase, self).setUp()

    def tearDown(self):
        super(DummyTestCase, self).tearDown()

    def test_function_name(self):
        self.assertEqual( "var", "bar" )
        self.assertEqual( "1937", "511" )

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

結果出力:

F
======================================================================
FAIL: test_function_name (__main__.DummyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\User\Downloads\test.py", line 77, in tearDown
    super(DummyTestCase, self).tearDown()
  File "D:\User\Downloads\test.py", line 29, in tearDown
    self.fail( '\n\n' + "\n\n".join( errors ) )
AssertionError: 

  File "D:\User\Downloads\test.py", line 80, in test_function_name
    self.assertEqual( "var", "bar" )
AssertionError 1: 'var' != 'bar'
- var
? ^
+ bar
? ^
 : 

  File "D:\User\Downloads\test.py", line 81, in test_function_name
    self.assertEqual( "1937", "511" )
AssertionError 2: '1937' != '511'
- 1937
+ 511
 : 

正しいスタックトレースキャプチャのためのより多くの代替ソリューションは、TestCase.assertEqual()を正しくオーバーライドして、正しいスタックトレースを生成する方法に投稿できますか?


0

PyUnitでこれを行う方法はないと思いますし、PyUnitがこのように拡張されるのを見たくありません。

私は、テスト関数ごとに1つのアサーション(またはより具体的にはテストごとに1つの概念をアサートする)に固執することを好みtest_addition()、4つの別々のテスト関数として書き直します。これが失敗した場合に、より有用な情報、与えるすなわちを

.FF.
======================================================================
FAIL: test_addition_with_two_negatives (__main__.MathTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_addition.py", line 10, in test_addition_with_two_negatives
    self.assertEqual(-1 + (-1), -1)
AssertionError: -2 != -1

======================================================================
FAIL: test_addition_with_two_positives (__main__.MathTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_addition.py", line 6, in test_addition_with_two_positives
    self.assertEqual(1 + 1, 3)  # Failure!
AssertionError: 2 != 3

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=2)

このアプローチが自分に合わないと判断した場合は、この回答が役立つ場合があります。

更新

更新された質問で2つの概念をテストしているようですが、これらを2つの単体テストに分割します。1つ目は、新しいオブジェクトの作成時にパラメータが保存されていることです。これには2つのアサーションがあります。1つはfor make、もう1つはmodel。です。最初が失敗した場合、2番目が成功したか失敗したかにかかわらず、それは明らかに修正する必要があります。この時点では関係ありません。

2番目の概念はもっと疑わしいです...あなたはいくつかのデフォルト値が初期化されているかどうかをテストしています。なぜですか?これらの値を実際に使用された時点でテストする方が便利です(使用されていない場合は、なぜそこにあるのですか?)。

これらのテストは両方とも失敗し、両方とも失敗するはずです。私がユニットテストをしているとき、私は成功するよりも失敗にはるかに興味があります。それは私が集中する必要がある場所だからです。

FF
======================================================================
FAIL: test_creation_defaults (__main__.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_car.py", line 25, in test_creation_defaults
    self.assertEqual(self.car.wheel_count, 4)  # Failure!
AssertionError: 3 != 4

======================================================================
FAIL: test_creation_parameters (__main__.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_car.py", line 20, in test_creation_parameters
    self.assertEqual(self.car.model, self.model)  # Failure!
AssertionError: 'Ford' != 'Model T'

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=2)

では、Car.test_initを4つの関数に分割しますか?
ブルースクリステンセン

@ブルースクリステンセン:私はおそらくそれを2つに分割するでしょう。しかし、それでも、あなたの主張が役立つかどうかはわかりません。回答するには更新を参照してください。
Johnsyweb 2011年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.