2

私のプロジェクトは、Python の を使用して外部 API へのさまざまな呼び出しを行いますurllib2.urlopen。単体テストに NoseTests を使用し、MiniMock を使用して への呼び出しをモックアップしていますurllib2.urlopen

モックコード:

from hashlib import md5
from os.path import dirname, join
from urllib2 import Request, urlopen

from minimock import mock, restore

def urlopen_stub(url, data=None, timeout=30):
    """
    Mock urllib2.urlopen and return a local file handle or create file if
    not existent and then return it.
    """

    if isinstance(url, Request):
        key = md5(url.get_full_url()).hexdigest()
    else:
        key = md5(url).hexdigest()
    data_file = join(dirname(__file__), 'cache', '%s.xml' % key)
    try:
        f = open(data_file)
    except IOError:
        restore() # restore normal function
        data = urlopen(url, data).read()
        mock('urlopen', returns_func=urlopen_stub, tracker=None) # re-mock it.
        with open(data_file, 'w') as f:
            f.write(data)
        f = open(data_file, 'r')
    return f

mock('urlopen', returns_func=urlopen_stub, tracker=None)

私は次のようにテストを実行しています:

from os.path import isfile, join
from shutil import copytree, rmtree

from nose.tools import assert_raises, assert_true

import urlopenmock

class TestMain(object):
    working = 'testing/working'

    def setUp(self):
        files = 'testing/files'
        copytree(files, self.working)

    def tearDown(self):
        rmtree(self.working)

    def test_foo(self):
        func_a_calling_urlopen()
        assert_true(isfile(join(self.working, 'file_b.txt')))

    def test_bar(self):
        func_b_calling_urlopen()
        assert_true(isfile(join(self.working, 'file_b.txt')))

    def test_bar_exception(self):
        assert_raises(AnException, func_c_calling_urlopen)

もともと、呼び出されたときに壊れた XML ファイルを返す別のモック ファイルをインポートした別のモジュールで、例外をチェックするテストがありましたurlopen。ただし、そのモック クラスをインポートすると、上記のクラスがオーバーライドされ、破損した XML が毎回使用されるため、すべてのテストが中断されます。

これは、例外テストモジュールが他のモジュールの後にロードされたため、そのインポートが最後に呼び出され、壊れた XML を返すモック関数が元のモック関数をオーバーライドしたためだと思います。

test_bar_exception が実行されたときに壊れた XML ファイルを使用して例外を発生させるようにモック コードに指示できるようにしたいと考えています。どうすればこれを行うことができますか?

4

2 に答える 2

3

それを使用する必要がある各テストでモック urlopen をセットアップおよび破棄し、そのエラー状態を処理するテスト用に壊れた xml ファイルを返すために別のモック urlopen を用意する必要があるようです。何かのようなもの:

class TestMain(object):
    # ...

    def test_foo(self):
        mock('urlopen', returns_func=urlopen_stub, tracker=None)
        func_a_calling_urlopen()
        assert_true(isfile(join(self.working, 'file_b.txt')))
        restore()

    # ...

    def test_bar_exception(self):
        mock('urlopen', 
                returns_func=urlopen_stub_which_returns_broken_xml_file, 
                tracker=None)
        assert_raises(AnException, func_c_calling_urlopen)
        restore()

ただし、テストで例外が発生し、restore()呼び出しに到達しない場合、上記には問題があります。でラップすることもできますがtry: ... finally:、それはテストごとに多くの面倒な作業です。

Michael Foord のモックライブラリを参照してください。

Pycon プレゼンテーション: http://blip.tv/file/4881513

urlopen の呼び出しを置き換えて復元するためのデコレータとコンテキスト マネージャのオプションを提供するpatchを見てください。とても気の利いた!

于 2011-05-01T00:15:21.093 に答える