2017-09-07 2 views
0

단위 테스트를 통해 조금 배 밖으로 나가는 것을 쉽게 인정합니다. 필자는 테스트를 통과하는 동안 내 솔루션이 멋지지 않다고 생각하며 누구나보다 깨끗한 솔루션이 있다면 궁금합니다. 가져온 모듈에서 Python Unittest 파일 조롱

클래스

는 테스트중인 :

class Config(): 

    def __init__(self): 
     config_parser = ConfigParser() 
     try: 
      self._read_config_file(config_parser) 
     except FileNotFoundError as e: 
      pass 

     self.token = config_parser.get('Tokens', 'Token',) 

    @staticmethod 
    def _read_config_file(config): 
     if not config.read(os.path.abspath(os.path.join(BASE_DIR, ROOT_DIR, CONFIG_FILE))): 
      raise FileNotFoundError(f'File {CONFIG_FILE} not found at path {BASE_DIR}{ROOT_DIR}') 

못생긴 시험 :

class TestConfiguration(unittest.TestCase): 

    @mock.patch('config.os.path.abspath') 
    def test_config_init_sets_token(self, mockFilePath: mock.MagicMock): 
     with open('mock_file.ini', 'w') as file: #here's where it gets ugly 
      file.write('[Tokens]\nToken: token') 
     mockFilePath.return_value = 'mock_file.ini' 

     config = Config() 

     self.assertEqual(config.token, 'token') 
     os.remove('mock_file.ini') #quite ugly 

편집 : 내 말 것은 내가 파일을 생성하는 대신 하나를 조롱하고 있습니다입니다. 누구든지 아스키 텍스트를 읽도록 데이터 세트를 가지고있는 동안 파일 객체 인 mock을 어떻게 알 수 있습니까? 수업은 깊이 묻혔습니다. 그 외의 방법으로 ConfigParser은 데이터를 .read()으로 설정하고 있습니다. 테스트가 "잘 작동"한다고해도 좋을 것입니다. 다른 테스트 행동에 대해 묻는 사람들을 위해

, 여기에이 클래스의 다른 테스트의 예 :

@mock.patch('config.os.path.abspath') 
def test_warning_when_file_not_found(self, mockFilePath: mock.MagicMock): 
    mockFilePath.return_value = 'mock_no_file.ini' 

    with self.assertRaises(FileNotFoundError): 
     config.Config._read_config_file(ConfigParser()) 

이 시간 내 주셔서 감사합니다.

+0

그건 무리가 아닙니다. 다른 솔루션의 경우'Config()'인스턴스를 인스턴스화하기 전에 모듈에서 설정할 수있는'BASE_DIR','ROOT_DIR' 및'CONFIG_FILE'을 만들 수 없습니까? 'Config' 클래스가 설정 파일의 경로를 선택적 매개 변수로 받아 들인다면 어떻게 될까요? – larsks

+1

필자는'ConfigParser'를 테스트 할 필요가 없다고 생각합니다. '_read_config_file'은 당신이하는 일을 의미하는 것을 수행하고, 설정 파일을 읽고, 실패 할 때 예외를 발생 시키도록 테스트해야합니다. –

+0

고마워, @ 잔디. 나도 그 유틸리티를 보았지만, 지금은 모든 config 관련 정보를 한 곳에 저장하는 것에 관심이 있습니다 (즉,'.ini' 파일의 이름을'.ini' 파일에 보관하십시오).). 정말로 문제가되는 것은'ConfigParser' 클래스가'.read'를 호출 할 때 파일 정보를 설정하는 방법입니다. 나는 ascii chars를 사용하여 데이터를 설정하는 조롱 된 파일 객체를 패치하려고하지만 클래스가 설계된 방식으로 직관적으로 만들지는 않습니다. self.assertRaises와 '(FileNotFoundError) :' 'config.Config._read_config_file (config.ConfigParser())' 을 - –

답변

0

발견했습니다! TextIOWrapper(BytesIO(b'<StringContentHere>'))

다음 부분에서, 그것은 open()를 호출하는 것을 볼 수 configparser 모듈을 파고 포함 :이 파일 오브젝트가 작성 될 수 있도록 from io import TextIOWrapper, BytesIO

:

나는 몇 수입으로 시작했다 주문 mock.patch 행동, 그리고 여기, 우리는 그것을 분리 unittest!

@mock.patch('configparser.open') 
def test_bot_init_sets_token(self, mockFileOpen: mock.MagicMock): 

    mockFileOpen.return_value = TextIOWrapper(BytesIO(b'[Tokens]\nToken: token')) 

    config = Config() 

    self.assertEqual(config.token, 'token') 
관련 문제