как издеваться над s3.Object для функции AWS lambda в AWS

#python #amazon-s3 #python-unittest

Вопрос:

У меня есть простая лямбда-функция, и поскольку я новичок в Python, я не могу писать тестовые примеры для этой функции. Итак, задача очень проста: я загружаю xml-документ в s3 и возвращаю URL-адрес. Ниже приведен код в основном файле python:

Редактировать 2: цель приведенного ниже кода состоит в том, чтобы сделать xml из полезной нагрузки JSON, которая передается в качестве корневого аргумента, и загрузить его в s3. у s3 уже есть задача s3-encora, и я должен загрузить output.xml. Я должен написать модульный тест для этого условия.

 def uploaddata(root):
    xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent="   ")
    string_out = io.StringIO()
    string_out.write(xmlstr)
    s3.Object('s3-encora-task', 'output.xml').put(Body=string_out.getvalue())
    location = boto3.client('s3').get_bucket_location(Bucket=bucket_name)['LocationConstraint']
    url = "https://s3-%s.amazonaws.com/%s/%s" % (location, bucket_name, 'output.xml')
    return url
 

Я получаю ошибку в строке:

 s3.Object('s3-encora-task', 'output.xml').put(Body=string_out.getvalue())
 

Ниже приведена ошибка:

вызовите NoCredentialsError() ботокор.исключения.Ошибка NoCredentialsError: Не удается найти учетные данные

У меня есть опыт написания тестовых классов Junit, но у меня возникают проблемы с сравнением(по способу написания) Junit и unittest, и поэтому я не могу сформулировать свой вопрос. Итак, у меня есть следующие вопросы:

  1. В моем файле python у меня нет класса.Я создаю экземпляр s3 таким образом вне методов: s3 = boto3.resource(‘s3’). Итак , как я могу поиздеваться над этим объектом s3 и перейти к методу, чтобы использовать макет объекта.
  2. В моем тестовом классе я импортирую основной python как : импортирую jsontoxmlconverter как конвертер, а затем использую конвертер.<> для модульного тестирования, но метод не принимает s3 в качестве аргумента, поэтому еще раз, как я могу передать макет объекта s3.
  3. Я прочитал несколько вещей об использовании moto для моделирования s3, но не смог понять, как передается объект, поэтому любая дополнительная информация об этом поможет.

заранее спасибо!!

Изменить 1: Ниже приведен текущий код в моем тестовом классе:

      import jsontoxmlconverter as converter
    def test_jsontoxml_happyflow(self):
        with open('jsonData.txt') as json_file:
            data = json.load(json_file)
        mock = Mock()
        mock.patch('converter.s3')
        result = converter.jsontoxml(data, context={})
 

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

1. Можно было бы привести рабочий пример, если бы вопрос включал любой тестовый код, который вы написали до сих пор, но суть в том, что вы хотите использовать mock.patch .

2. Я на самом деле теряюсь в том, как это сделать в первую очередь. Я добавляю код, который у меня есть до сих пор в моем тестовом классе. Спасибо

3. Ваш тест вообще не вызывает uploaddata функцию, так почему вы беспокоитесь о том, как издеваться над s3 в этой функции?

4. Извините, uploaddata вызывается из функции jsontoxml, и поэтому возникает ошибка.

Ответ №1:

Воспользуйся mock.patch :

 import jsontoxmlconverter as converter
from mock import patch

def test_jsontoxml_happyflow(self):
    with patch('jsontoxmlconverter.s3') as mock_s3:
        # make whatever adjustments to mock_s3 as needed
        result = converter.uploaddata("foo")
 

Обратите внимание, что вам нужно указать patch , в каком модуле вы хотите установить исправление s3. При использовании patch в качестве контекстного менеджера исправление применяется только в контексте, что позволяет легко изолировать подобные изменения и гарантировать, что они не повлияют на другие тесты. mock_s3 Объект, доступный в контексте, — это mock.Mock объект, который занимает место s3 ; вы можете свободно переназначить его атрибуты перед вызовом функции, которая будет зависеть от них.

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

1. с исправлением(«jsontoxmlconverter.s3») как mock_s3: в этой строке jsontoxmlconverter.s3 -> jsontoxmlconverter-это файл python, и s3 должен быть глобальной переменной? Также, например, для следующих строк кода в моем основном классе: s3.Object(‘s3-encora-задача’, ‘output.xml’).поместите(Тело=string_out.getvalue()) местоположение = boto3.клиент(‘s3’).get_bucket_location(Ведро=имя_букета)[‘LocationConstraint’] итак, как я могу использовать mock_s3, чтобы издеваться над этими 2 строками?

2. Мне не ясно, пытались ли вы запустить код, или если да, то чем результат отличался от того, что вы искали. Я думаю, что простое исправление s3 модуля с помощью макета должно, по крайней мере, предотвратить возникновение исключения; заставить макет объекта делать что-то более полезное зависит от вас, так как вы не описали, что вы хотите, чтобы насмехались s3 на самом деле.

3. Если бы вы предоставили минимальный воспроизводимый пример (например, предоставили тест и весь тестируемый код) и просто сказали, что вы хотите, чтобы это произошло, на данный момент у вас, вероятно, был бы полностью рабочий код-если вы просто скажете «как я могу использовать это для насмешек?», вы получите общий пример (например, то, что я предоставил) и вам придется заполнить пробелы самостоятельно. 🙂 Предоставленный вами код и ваше описание слишком неполны, чтобы я мог исправить код для вас.

4. Я обновил Edit2 с комментариями. Не могли бы вы, пожалуйста, проверить.

5. Здесь все еще недостаточно кода для реального запуска. У вас все еще есть тест, который вызывает функцию, которую вы не определили, и вы все еще не сказали, что именно вы хотите, чтобы тест охватывал (что трудно сделать, так как вы не делитесь фактическим кодом, который вы тестируете). Правки делают вещи менее ясными, не более.