2016-07-24 2 views
1

내가 (comicfile.py에서) 다음과 같습니다 파이썬 방법이 있습니다클래스 함수의 반환 값을 조롱하려면 어떻게해야합니까?

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 

나는 이것에 대한 단위 테스트를 (이미 prune_dirs을 테스트 한) 작성하는 중이 야를, 그래서이 무엇입니까 나는 (test_comicfile.py)이 있습니다

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) 

좋아, 그럼:이 테스트를 실행하면

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()) 

, 나는 다음을 얻을은 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을 처리하는 대신이 하나의 기능 만 테스트하도록 namelist 메서드를 재정의하는 방법을 생각할 수없는 것 같습니다. 게다가.

+0

코드가 혼동 스럽습니다. 'ComicFile'과 'comicfile'은 1 클래스 (한 번 철자 오류가 있음) 또는 2입니까? 'self.Zipfile'에 의해 첫 번째 스 니펫에서 'Zipfile'을해야합니까? 세부 사항을 모른 채 모의가 필요한지 궁금합니다. 각 테스트는 다른 모든 것이 작동한다고 가정해야합니다. 테스트가 실패 할 때만 질문합니다. 뭔가를 조롱하는 긍정적 인 이유가 필요합니다. 예를 들어 '호출이 테스트 설정에서 실패합니다.'또는 '실제 객체 호출에 너무 많은 시간이나 공간이 필요합니다'또는 '반환이 결정적이지 않습니다'. –

+0

내가 Pythonic이 아닌 명명 규칙을 사용하고있을 가능성이 있습니다. 'ComicFile'은 클래스이고,'comicfile'은 클래스를 포함하는 모듈입니다. 'ZipFile'은'from zipfile import ZipeFile'을 통해 가져옵니다. 나는 * 내가 생각하기에 모의가 필요하다고 생각한다. 필자가 이것을 테스트하기 위해서는 실제로 파일 시스템에 zip 파일이 있어야하고, zip 파일 객체가' namelist',이 함수는 정확하게 파일의 수를 센다. – Chuck

+0

mock은 특히 문맥 관리자와 관련하여 혼란 스럽습니다. – dm03514

답변

2

ZipFilecontext 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'>

:


한 트릭은 모의 레지스터가 모든 통화가로했을 때,이 예에서 그것에서 전화를 가지고 말하는 것입니다 개체를 모두 바꾸기 ()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

관련 문제