Макет полезной нагрузки электронной почты на python

#python #mocking #python-unittest

#python #издевательство #python-unittest

Вопрос:

Я пишу модульные тесты для функции, которая должна получать все допустимые вложения в сообщении электронной почты. Моя функция имеет следующее поведение:

 def extract_attachments(local_file):
    email_file = open(local_file, "r")
    msg = email.message_from_file(email_file)        
    attchs = [x for x in msg.get_payload() if x.get_filename() is not None]
    for attch in attchs:
        filename = attch.get_filename()
        if filename not in VALID_ATTACHMENTS:
            raise Exception('Invalid attachment', filename)        
    return attchs
  

Как я могу заставить эту функцию возвращать некоторый объект с помощью функции get_filename() ?

Я пытаюсь это исправить, но получаю сообщение об ошибке 'list' object has no attribute 'get_payload' .

 @patch("mail_extractor.process_email.email")
@patch("builtins.open")
def test_extract_attachments(open, email):
    email.message_from_file.return_value = []
    email.get_payload.return_value = ['1.xml']
    result = process_email.extract_attachments('mock')
    assert len(result) == 1
  

Ответ №1:

Описанная вами нотация специфична для объектов, и то, что вы пытаетесь ей придать, — это метод. Вам нужно будет определить класс:

 class MyClass:
    def get_filename():
        # some logic
  

Затем вы сможете создать экземпляр вашего объекта:

 x = MyClass()
x.get_filename()
  

Это отвечает на ваш вопрос?

Комментарии:

1. Итак, мне нужно написать класс для макета методов электронной почты?

2. Я думаю, что на самом деле вы намеревались сделать вот что: attchs = [msg for x in msg.get_payload() if msg.get_filename() is not None] таким образом, у вас все еще будут объекты msg, просто отфильтрованные по результатам get_filename . Я предполагаю, что get_payload() возвращает список, а не объект.

3. Я понял это. Позвольте мне попробовать одну вещь

Ответ №2:

Способ, которым вы настроили свои mocks, не совсем правильный. message_from_file() Вызов должен вернуть сообщение, в то время как вы возвращаете список — отсюда и ошибка, которую вы видите.

Вы должны настроить макет сообщения вместе с макетом вложения, чтобы удовлетворять вызовам, которые ожидает выполнить код.

Например:

 @patch("mail_extractor.process_email.email")
@patch("builtins.open")
def test_extract_attachments(open, email):
    # Configure the mock message and its attachment
    mock_message = Mock()
    mock_attachment = Mock()
    mock_attachment.get_filename.return_value = '1.xml'
    mock_message.get_payload.return_value = [mock_attachment]

    # Configure message_from_file to return the mock message
    email.message_from_file.return_value = mock_message

    result = process_email.extract_attachments('mock')
    assert len(result) == 1