Как написать модульный тест для функции, которая обращается к ресурсам aws? - PullRequest
2 голосов
/ 26 марта 2019

У меня есть функция, которая обращается к нескольким aws ресурсам, и теперь мне нужно протестировать эту функцию, но я не знаю, как имитировать эти ресурсы.

Я пробовал следовать github из aws-sdk-Мок, но там не так много.

function someData(event, configuration, callback) {

    // sts set-up
    var sts = new AWS.STS(configuration.STS_CONFIG);

    sts.assumeRole({
      DurationSeconds: 3600,
      RoleArn: process.env.CROSS_ACCOUNT_ROLE,
      RoleSessionName: configuration.ROLE_NAME
    }, function(err, data) {
      if (err) {
        // an error occurred
        console.log(err, err.stack);
      } else {
        // successful response

        // resolving static credential
        var creds = new AWS.Credentials({
          accessKeyId: data.Credentials.AccessKeyId,
          secretAccessKey: data.Credentials.SecretAccessKey,
          sessionToken: data.Credentials.SessionToken
        });

         // Query function
         var dynamodb = new AWS.DynamoDB({apiVersion: configuration.API_VERSION, credentials:  creds, region: configuration.REGION});
         var docClient = new AWS.DynamoDB.DocumentClient({apiVersion: configuration.API_VERSION, region: configuration.REGION, endpoint: configuration.DDB_ENDPOINT, service: dynamodb });

            // extract params
            var ID = event.queryStringParameters.Id;
            console.log('metrics of id ' + ID);

            var params = {
                TableName: configuration.TABLE_NAME,
                ProjectionExpression: configuration.PROJECTION_ATTR,
                KeyConditionExpression: '#ID = :ID',
                ExpressionAttributeNames: {
                    '#ID': configuration.ID
                },
                ExpressionAttributeValues: {
                    ':ID': ID
                }
            };

            queryDynamoDB(params, docClient).then((response) => {
                console.log('Params: ' + JSON.stringify(params));
                // if the query is Successful
                if( typeof(response[0]) !== 'undefined'){
                    response[0]['Steps'] = process.env.STEPS;
                    response[0]['PageName'] = process.env.STEPS_NAME;
                }
                console.log('The response you get', response);
                var success = {
                    statusCode: HTTP_RESPONSE_CONSTANTS.SUCCESS.statusCode,
                    body: JSON.stringify(response),
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    isBase64Encoded: false
                };
                return callback(null, success);
            }, (err) => {
                // return internal server error
                return callback(null, HTTP_RESPONSE_CONSTANTS.BAD_REQUEST);
            });
      }

    });

}

Это функция lambda, которую мне нужно проверить, здесь также используется некоторая переменная env.

Теперь я попытался написать модульный тест для вышеуказанной функции с использованием aws-sdk-mock но все же я не могу понять, как на самом деле это сделать.Любая помощь будет оценена.Ниже мой тестовый код

describe('test getMetrics', function() {

    var expectedOnInvalid = HTTP_RESPONSE_CONSTANTS.BAD_REQUEST;

    it('should assume role ', function(done){
        var event = {
          queryStringParameters : {
              Id: '123456'
          }
        };

        AWS.mock('STS', 'assumeRole', 'roleAssumed');
        AWS.restore('STS');
        AWS.mock('Credentials', 'credentials');
        AWS.restore('Credentials');
        AWS.mock('DynamoDB.DocumentClient', 'get', 'message');
        AWS.mock('DynamoDB', 'describeTable', 'message');
        AWS.restore('DynamoDB');
        AWS.restore('DynamoDB.DocumentClient');

        someData(event, configuration, (err, response) => {
            expect(response).to.deep.equal(expectedOnInvalid);
            done();
        });


    });


});

Я получаю следующую ошибку:

{ MultipleValidationErrors: There were 2 validation errors:
* MissingRequiredParameter: Missing required key 'RoleArn' in params
* MissingRequiredParameter: Missing required key 'RoleSessionName' in params

Ответы [ 3 ]

1 голос
/ 26 марта 2019

Я категорически не согласен с ответом @ ttulka, поэтому решил добавить и свой.

Учитывая, что вы получили событие в своей функции Lambda, весьма вероятно, что вы обработаете событие и затем вызовете какой-либо другой сервис. Это может быть вызов S3, DynamoDB, SQS, SNS, Kinesis ... Вы называете это. Что тут утверждать?

Правильные аргументы!

Рассмотрим следующее событие:

{
   "data": "some-data",
   "user": "some-user",
   "additionalInfo": "additionalInfo"
}

Теперь представьте, что вы хотите вызвать documentClient.put и хотите убедиться, что передаваемые вами аргументы верны. Скажем также, что вы НЕ хотите, чтобы атрибут additionalInfo был сохранен, поэтому где-то в вашем коде у вас будет это, чтобы избавиться от этого атрибута

delete event.additionalInfo

право

Теперь вы можете создать модульный тест для утверждения , что правильные аргументы были переданы в documentClient.put, что означает, что конечный объект должен выглядеть следующим образом:

 {
   "data": "some-data",
   "user": "some-user"
 }

Ваш тест должен утверждать, что documentClient.put был вызван с JSON, который по глубине равен JSON выше.

Если вы или любой другой разработчик по какой-либо причине удалите строку delete event.additionalInfo, тесты начнут проваливаться.

И это очень сильно! Если вы убедитесь, что ваш код работает так, как вы ожидаете, вам вообще не нужно беспокоиться о создании интеграционных тестов.

Теперь, если Lambda-потребитель SQS ожидает, что в теле сообщения будет какое-то поле, производитель Lambda всегда должен позаботиться об этом, чтобы убедиться, что в очереди сохраняются правильные аргументы. Я думаю, что теперь вы поняли идею, верно?

Я всегда говорю своим коллегам, что если мы сможем создать правильных модульных тестов, мы должны быть хороши в 95% случаев, оставляя интеграционные тесты неактивными. Конечно, лучше иметь и то и другое, но, учитывая количество времени, затрачиваемое на создание интеграционных тестов, таких как настройка сред, учетных данных, иногда даже разных учетных записей, не стоит. Но это только мое мнение. И вы, и @ttulka более чем согласны.

Теперь вернемся к вашему вопросу:

Вы можете использовать Sinon для проверки и утверждения аргументов в ваших лямбда-функциях. Если вам нужно смоделировать сторонний сервис (например, DynamoDB, SQS и т. Д.), Вы можете создать фиктивный объект и заменить его в тестируемом файле, используя Rewire . Обычно это та дорога, по которой я езжу, и до сих пор она была великолепной.

1 голос
/ 09 апреля 2019

Попробуйте установить aws-sdk модуль явно. Структуры проекта, которые не включают aws-sdk в папке проекта node_modules верхнего уровня, не будут должным образом смоделированы.Примером этого может быть установка aws-sdk во вложенном каталоге проекта.Вы можете обойти это, явно указав путь к вложенному aws-sdk модулю, используя setSDK().

const AWSMock = require('aws-sdk-mock');
import AWS = require('aws-sdk');
AWSMock.setSDKInstance(AWS);

Подробнее об этом: Прочитайте документацию aws-sdk-mock Они объяснили это еще лучше.

0 голосов
/ 26 марта 2019

Я рассматриваю модульное тестирование как способ проверить, соблюдаются ли правила вашего домена (бизнеса).

Поскольку ваша Lambda содержит исключительно интеграцию сервисов AWS, нет смысла писать для нее модульный тест.

Чтобы смоделировать все средства, ваш тест будет проверять только связь между этими имитациями - такой тест не имеет значения.

Внешние ресурсы означают ввод / вывод, именно на это ориентируется интеграционное тестирование.

Написание интеграционных тестов и их запуск в составе конвейера интеграции с реальными развернутыми ресурсами.

...