2016-07-24 18 views
1

私は(comicfile.pyで)このようになりますPythonでの方法があります:私は(私はすでにprune_dirsをテストしてみた)、このためのユニットテストを書くことをしようとしている、そしてそのために、これは何であるクラスの関数の戻り値をモックするにはどうすればよいですか?

from zipfile import ZipFile 

... 

class ComicFile(): 
    ... 

    def page_count(self): 
     """Return the number of pages in the file.""" 
     if self.file == None: 
      raise ComicFile.FileNoneError() 

     if not os.path.isfile(self.file): 
      raise ComicFile.FileNotFoundError() 

     with ZipFile(self.file) as zip: 
      members = zip.namelist() 
      pruned = self.prune_dirs(members) 
      length = len(pruned) 
      return length 

を私は(test_comicfile.py)持っている:私はこのテストを実行すると

import unittest 
import unittest.mock 

import comicfile 

... 

class TestPageCount(unittest.TestCase): 

    def setUp(self): 
     self.comic_file = comicfile.ComicFile() 

    @unittest.mock.patch('comicfile.ZipFile') 
    def test_page_count(self, mock_zip_file): 
     # Store as tuples to use as dictionary keys. 
     members_dict = {('dir/', 'dir/file1', 'dir/file2'):2, 
         ('file1.jpg', 'file2.jpg', 'file3.jpg'):3 
     } 

     # Make the file point to something to prevent FileNoneError. 
     self.comic_file.file = __file__ 

     for file_tuple, count in members_dict.items(): 
      mock_zip_file.return_value.namelist = list(file_tuple) 
      self.assertEqual(count, self.comic_file.page_count()) 

、私は次の取得:

F..ss.... 
====================================================================== 
FAIL: test_page_count (test_comicfile.TestPageCount) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/unittest/mock.py", line 1157, in patched 
    return func(*args, **keywargs) 
    File "/Users/chuck/Dropbox/Projects/chiv/chiv.cbstar/test_comicfile.py", line 86, in test_page_count 
    self.assertEqual(count, self.comic_file.page_count()) 
AssertionError: 2 != 0 

---------------------------------------------------------------------- 
Ran 9 tests in 0.010s 

FAILED (failures=1, skipped=2) 

OK、そうself.comic_file.page_count()0を返します。私はmembers = zip.namelist()の後に次の行をpage_countに置こうとしました。テスト中

print('\nmembers -> ' + str(members)) 

、私はこれを取得:

members -> <MagicMock name='ZipFile().__enter__().namelist()' id='4483358280'> 

私はユニットテストに非常に新たなんだとunittest.mockを使用して、非常に漠然としていますが、私の理解がようmock_zip-file.return_value.namelist = list(file_tuple)がそれを作っているということですZipFileクラスのnamelistメソッドは、file_tupleの各コンテンツを順番に返します。それはです私は分かりません。

私がここでやろうとしていることははっきりしていると思いますが、私のユニットテストではZipFileを処理する代わりにこの1つの機能しかテストしないように、namelistメソッドをオーバーライドする方法を見つけられないようです。同じように。

+0

コードが混乱します。 'ComicFile'と 'comicfile'は1クラス(スペルミス)または2ですか?最初のスニペットで 'Zipfile'を 'self.Zipfile'で行う必要がありますか?細部を知らずに、私はあなたがモックを必要とするかどうか疑問に思います。それぞれのテストは、他のすべてが動作することを前提とする必要がありあなたは、テストが失敗したときにそれだけを質問します。何かを模擬する肯定的な理由が必要です。たとえば、 '呼び出しはテスト設定で失敗するか、'実際のオブジェクトを呼び出すには時間と空間があまりにも多くかかります。 'または'戻り値が確定的ではありません '。 –

+0

私はそれらに準拠しようとしていますが、私はPython以外の命名規則を使用している可能性があります。 'ComicFile'はクラス、' comicfile'はクラスを含むモジュールです。 'ZipFile'は' from zipfile import ZipeFile'を介してインポートされます。私は思う*私は私が実際にファイルシステムにzipファイルを持っている必要があり、私はちょうどそれをテストしたい、私はしない場合、私はモックする必要があると思う* zipファイルオブジェクトが返す場合、この関数はファイルの数を正しく数えます。 – Chuck

+0

モックは混乱しています。特に、コンテキストマネージャに関しては混乱します。 – dm03514

答えて

2

ZipFileは、context managerとしてインスタンス化されます。 mockには__enter__メソッドを参照する必要があります。あなたが何をしようとして

mock_zip_file.return_value.__enter__.return_value.namelist.return_value = list(file_tuple)

非常に明確であるが、コンテキストマネージャは、モックが複雑に。これは、あなたが嘲笑登録であなたを導くことができる

members -> <MagicMock name='ZipFile().__enter__().namelist()' id='4483358280'>


1つのトリックは、模擬レジスタはすべてのコールがそれに行われたときに、この例では、それはで電話を持っていると言っているということですオブジェクトを交換します。()return_valueに置き換えます。

+0

OK、まず、tyvm。私はコピーして貼り付け、テストを行いました。コード全体に配置したプリントは、私が期待しているもの(嘲笑されたメンバー)を示しています。もちろん、私はまだ理解していない*なぜそれが動作する、それは私がそれを把握するまで私をバグに行くだろう。私は 'mock'ドキュメントを数回読んだことがありますが、あなたがリンクした記事を見てみましょう。おそらく、そのようなコードの意味を理解する助けになるでしょう。 – Chuck

+0

私は(今)理解しています。 'with 'ブロックなしで' zip = ZipFile ... 'だけを' zip'に設定すると、 'mock_zip_file.return_value.namelist.return_value = list(file_tuple)'が働いていました。あなたが引用した 'print'の' __enter__'は、 'namevalue'に到達するために使っていたパスが間違っていると警告していたはずです。 – Chuck

関連する問題