1

ノーズテストを使おうとしていますが、以下のテストケースを実行すると

import unittest

class TestSuite(unittest.TestCase):
    b = []

    def setUp(self):
        self.b.extend([10, 20])

    def tearDown(self):
        self.b = []

    def test_case_1(self):
        self.b.append(30)
        assert len(self.b) == 3
        assert self.b == [10, 20, 30]

    def test_case_2(self):
        self.b.append(40)
        assert len(self.b) == 3
        assert self.b == [10, 20, 40]

しかし、すべてのテストケースが合格するわけではありません

$> nosetest test_module.py
.F
======================================================================
FAIL: test_case_2 (test_module2.TestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/knt/test_module2.py", line 19, in test_case_2
    assert len(self.b) == 3
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

何があったの ???test_case_1を実行した後、tearDownが呼び出されることを期待していself.bます[]。したがって、次のテストケースではtest_case_2setUp実行して、self.bです[10, 20]

しかし実際には、のsetUp値でself.b is [10, 20, 30]

どうしてか分かりません。ステートメントには問題があるに違いないと思いますself.b = []

何か関連するポインタだと思いますか?私はまだそれを理解していませんでしたが、私はこのバグを修正する方法を見つけました。に変更self.b = []するだけdel self.b[:]です。

誰かが私が問題を見つけるのを手伝ってくれる?どうもありがとう。

4

3 に答える 3

4

unitestsがどのように機能するか、Pythonでクラスフィールドがどのように機能するかという問題を私が知る限り、ここでは簡単なテストを行います。

class A:
    b = []
    def reset(self):
        self.b = []

a = A()    
a.b.append(3) # we are actually accessing the class variable here
print A.b is a.b # True
print a.b # [3] same here
a.reset() # We just hid the class variable with our own which points to []
print A.b is a.b # False as expected.
print a.b # [] we think its being clear but rather we are using our own not the class variable

b = A()
print b.b # [3] b here is using the class that a previously modified but is no longer pointing to
print b.b is A.b # True

# Also note
c = A()
d = A()
print c.b is d.b # True, since both are using the same class variable.

unittestは、オブジェクトを複数回作成していると思います。テスト関数ごとに、オブジェクトを作成し、クラス変数にアクセスするセットアップを起動し、テストを実行し、単にオブジェクトを非表示にするティアダウンを呼び出し、別のオブジェクトを作成し、同じクラス変数にアクセスするセットアップを呼び出します。以前のオブジェクトは変更され、その破棄によって自分自身にバインドされた新しいインスタンスが作成され、クラスバージョンが非表示になったため影響を受けませんでした。

usingself内で常にメンバーフィールドを宣言します__init__

def __init__(self):
    self.b = []

このように、すべてのインスタンスが独自のコピーを持ちますが、それを継承しているため、ここではこれを行うことはできませんunittest.TestCasesetUp

import unittest
class TestSuite(unittest.TestCase):
    def setUp(self):
        self.b = [10, 20]

    def tearDown(self):
        self.b = []

    def test_case_1(self):
        self.b.append(30)
        assert len(self.b) == 3
        assert self.b == [10, 20, 30]

    def test_case_2(self):
        self.b.append(40)
        assert len(self.b) == 3
        assert self.b == [10, 20, 40]
于 2012-06-16T09:03:28.383 に答える
2

問題は、2行目のクラス属性です。

b = []

これはクラスの属性ですTestSuite。Nosetestsは、クラスの新しいインスタンスを作成してTestSuiteから、を呼び出しますsetUp。で、クラスのクラス属性setUpを変更します。TestSuite

self.b.extend([10, 20])

次に、でtearDown、最初のテストが実行された後、新しいリストを作成し、それを新しいインスタンス属性に割り当てます。この属性は、たまたま呼び出されbます。

self.b = []

これにより、クラス属性はまったく変更されません。このインスタンスからさらにアクセスしようとすると、クラス属性ではなく、インスタンスself.b属性が返されます。

ただし、これは効果がありません。次に発生するのは、nosetestsが、で設定したインスタンス属性TestSuiteの新しい空のリストを含む、の現在のインスタンスを破棄することです。btearDown

TestSuite次に、nosetestsは、 2番目のテストを実行するために、クラスの新しいインスタンスを作成します。ただし、最初のテストの実行中に変更されたため、クラスにTestSuiteはまだを含むb クラス属性があります。[10, 20, 30]

次に、nosetestssetUpメソッドが実行され、のクラス属性に追加1020れます。次に、2番目のテストが実行され、のクラス属性に追加されます。2番目のテストは、そのクラス属性に6つの項目が見つかったため、失敗します。TestSuiteb40TestSuite

[10,20,30,10,20,40]

が機能する理由del self.b[:]は、と同様appendに、新しいインスタンス属性を作成するのではなく、クラスdel属性を変更するためです。

クラスとインスタンスの違い、およびクラス属性とインスタンス属性の違いを理解していることを確認してください。理解していないと、Pythonを使用している限り、同様の問題に悩まされます。

于 2012-06-16T11:13:36.323 に答える
0

さて、交換してみてください:

self.b.extend([10,20])

self.b = [10,20]

そして多分クラス変数を捨てる、あなたはそれを必要としない、そしてそれがこれが起こる理由かもしれない。

于 2012-06-16T08:41:37.760 に答える