5

一連のユーザー定義オブジェクトを処理しています。次のようになります。

class Thing(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

私が現在テストしているメソッドには、次のような機能があります。

def my_function(things):
    x_calc = calculate_something(t.x for t in things)
    y_calc = calculate_something(t.y for t in things)
    return x_calc / y_calc

私が直面している問題は、への呼び出しをテストすることcalculate_somethingです。私はこれらの呼び出しが起こったことを断言したいと思います、そのようなもの:

calculateSomethingMock.assert_any_call(the_sequence)

に渡されるシーケンスの順序は気にしませんcalculate_somethingが、要素がすべて存在することは気にします。ジェネレーター関数をへの呼び出しでラップすることはできますがset、テストでに渡されるシーケンスのタイプを指定する必要があるとは思いませんcalculate_something。私はそれにどんな種類のシーケンスも渡すことができるはずです。あるいは、ジェネレータ構文を使用する代わりにシーケンスを生成するメソッドを作成し、そのメソッドをモックすることもできますが、それはやり過ぎのようです。

このアサーションを最適に構造化するにはどうすればよいですか、またはここでのテストの問題は、構造化が不十分なコードを示していますか?

私はPython2.7.3とMock1.0.1を使用しています。

(コメントを余儀なくされていると感じている人は、私が最後にテストを行っていること、そしてこれが最高のプラクティスとは見なされていないことを認識しています。)

編集:

「GregoryMoeckによるモックオブジェクトを取得しない理由」というタイトルのこの素晴らしい講演を見た後、私はメソッドをモックするべきかどうかを再考しましたcalculate_something

4

2 に答える 2

7

モックのドキュメントを見ると、あなたが望むことをするcall_args_listがあります。

したがってcalculate_something、テストでモックアウトします。

calculate_something = Mock(return_value=None)

終了したら、次のようmy_functionにして、渡された引数を確認できます。

calculate_something.call_args_list

これは、それに対して行われたすべての呼び出しのリストを返します (対応する要素が渡されます)。

編集

(申し訳ありませんが、時間がかかりました。マシンにPython3.3をインストールする必要がありました)

mymodule.py

class Thing:
    ...
def calculate_something:
    ...

def my_function(things):
    # Create the list outside in order to avoid a generator object
    # from being passed to the Mock object.

    xs = [t.x for t in things]
    x_calc = calculate_something(xs)

    ys = [t.y for t in things]
    y_calc = calculate_something(ys)
    return True

test_file.py

import unittest
from unittest.mock import patch, call
import mymodule



class TestFoo(unittest.TestCase):

    # You can patch calculate_something here or
    # do so inside the test body with 
    # mymodule.calcualte_something = Mock()
    @patch('mymodule.calculate_something')
    def test_mock(self, mock_calculate):

        things = [mymodule.Thing(3, 4), mymodule.Thing(7, 8)]

        mymodule.my_function(things)

        # call_args_list returns [call([3, 7]), call([4, 8])]
        callresult = mock_calculate.call_args_list


        # Create our own call() objects to compare against
        xargs = call([3, 7])
        yargs = call([4, 8])

        self.assertEqual(callresult, [xargs, yargs])

        # or
        # we can extract the call() info
        # http://www.voidspace.org.uk/python/mock/helpers.html#mock.call.call_list
        xargs, _ = callresult[0]
        yargs, _ = callresult[1]

        xexpected = [3, 7]
        yexpected = [4, 8]

        self.assertEqual(xargs[0], xexpected)
        self.assertEqual(yargs[0], yexpected)

if __name__ == '__main__':
    unittest.main()
于 2013-01-22T19:40:02.147 に答える