【问题标题】:Mock AWS services for NodeJS unit tests用于 NodeJS 单元测试的模拟 AWS 服务
【发布时间】:2018-03-22 17:38:42
【问题描述】:

我正在考虑为 NodeJS 项目设置一些单元测试,但我想知道如何模拟我对 AWS 服务的使用。我使用的范围很广:SNS、SQS、DynamoDB、S3、ECS、EC2、Autoscaling 等。有人对我如何模拟这些有任何好的指导吗?

【问题讨论】:

    标签: node.js amazon-web-services mocking


    【解决方案1】:

    我只是花了几个小时试图让 AWS SQS 模拟工作,没有诉诸 aws-sdk-mock 要求在函数中导入 aws-sdk 客户端。

    AWS.DynamoDB.DocumentClient 的模拟非常简单,但 AWS.SQS 的模拟让我感到困惑,直到我发现使用 rewire 的建议。

    我的 lambda 将错误消息移动到 SQS FailQueue(而不是让 Lambda 失败并将消息返回到常规队列进行重试,然后在 maxRetries 之后返回 DeadLetterQueue)。模拟以下 SQS 方法所需的单元测试:

    • SQS.getQueueUrl
    • SQS.sendMessage
    • SQS.deleteMessage

    我会尽量保持这个示例代码简洁,同时仍然包含所有相关部分:

    我的 AWS Lambda (index.js) 的片段:

    const AWS = require('aws-sdk');
    AWS.config.update({region:'eu-west-1'});
    const docClient = new AWS.DynamoDB.DocumentClient();
    const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
    // ...snip
    

    精简的 Lambda 事件记录 (event.json)

    {
        "valid": {
            "Records": [{
                "messageId": "c292410d-3b27-49ae-8e1f-0eb155f0710b",
                "receiptHandle": "AQEBz5JUoLYsn4dstTAxP7/IF9+T1S994n3FLkMvMmAh1Ut/Elpc0tbNZSaCPYDvP+mBBecVWmAM88SgW7iI8T65Blz3cXshP3keWzCgLCnmkwGvDHBYFVccm93yuMe0i5W02jX0s1LJuNVYI1aVtyz19IbzlVksp+z2RxAX6zMhcTy3VzusIZ6aDORW6yYppIYtKuB2G4Ftf8SE4XPzXo5RCdYirja1aMuh9DluEtSIW+lgDQcHbhIZeJx0eC09KQGJSF2uKk2BqTGvQrknw0EvjNEl6Jv56lWKyFT78K3TLBy2XdGFKQTsSALBNtlwFd8ZzcJoMaUFpbJVkzuLDST1y4nKQi7MK58JMsZ4ujZJnYvKFvgtc6YfWgsEuV0QSL9U5FradtXg4EnaBOnGVTFrbE18DoEuvUUiO7ZQPO9auS4=",
                "body": "{ \"key1\": \"value 1\", \"key2\": \"value 2\", \"key3\": \"value 3\", \"key4\": \"value 4\", \"key5\": \"value 5\" }",
                "attributes": {
                    "ApproximateReceiveCount": "1",
                    "SentTimestamp": "1536763724607",
                    "SenderId": "AROAJAAXYIAN46PWMV46S:steve.goossens@bbc.co.uk",
                    "ApproximateFirstReceiveTimestamp": "1536763724618"
                },
                "messageAttributes": {},
                "md5OfBody": "e5b16f3a468e6547785a3454cfb33293",
                "eventSource": "aws:sqs",
                "eventSourceARN": "arn:aws:sqs:eu-west-1:123456789012:sqs-queue-name",
                "awsRegion": "eu-west-1"
            }]
        }
    }
    

    精简的单元测试文件(test/index.test.js):

    const AWS = require('aws-sdk');
    const expect = require('chai').expect;
    const LamdbaTester = require('lambda-tester');
    const rewire = require('rewire');
    const sinon = require('sinon');
    
    const event = require('./event');
    const lambda = rewire('../index');
    
    let sinonSandbox;
    
    function mockGoodSqsMove() {
        const promiseStubSqs = sinonSandbox.stub().resolves({});
        const sqsMock = {
            getQueueUrl: () => ({ promise: sinonSandbox.stub().resolves({ QueueUrl: 'queue-url' }) }),
            sendMessage: () => ({ promise: promiseStubSqs }),
            deleteMessage: () => ({ promise: promiseStubSqs })
        }
        lambda.__set__('sqs', sqsMock);
    }
    
    describe('handler', function () {
        beforeEach(() => {
            sinonSandbox = sinon.createSandbox();
        });
    
        afterEach(() => {
            sinonSandbox.restore();
        });
    
        describe('when SQS message is in dedupe cache', function () {
            beforeEach(() => {
                // mock SQS
                mockGoodSqsMove();
                // mock DynamoDBClient
                const promiseStub = sinonSandbox.stub().resolves({'Item': 'something'});
                sinonSandbox.stub(AWS.DynamoDB.DocumentClient.prototype, 'get').returns({ promise: promiseStub });
            });
    
            it('should return an error for a duplicate message', function () {
                return LamdbaTester(lambda.handler)
                    .event(event.valid)
                    .expectReject((err, additional) => {
                        expect(err).to.have.property('message', 'Duplicate message: {"Item":"something"}');
                    });
            });
        });
    });
    

    【讨论】:

      【解决方案2】:

      看看LocalStack。它提供了一个易于使用的测试/模拟框架,用于通过在本地机器或 Docker 中启动与 AWS 兼容的 API 来开发与 AWS 相关的应用程序。它支持两打 AWS API,其中包括 SQS。它确实是一个很棒的功能测试工具,无需在 AWS 中使用单独的环境。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-21
        • 2020-03-17
        相关资源
        最近更新 更多