简体   繁体   English

如何使用 Jest 和 TypeScript 模拟 Twilio 进行单元测试

[英]How to mock Twilio using Jest and TypeScript for unit testing

I need your help to mock a twilio service which sends a message, using jest to mock the service I have the next code:我需要您的帮助来模拟发送消息的 twilio 服务,使用玩笑来模拟服务我有下一个代码:

import { SQSEvent } from "aws-lambda";
import { GetSecretValueResponse } from "aws-sdk/clients/secretsmanager";

export async function sendSms(event: SQSEvent, data: GetSecretValueResponse) {
    const secrets = JSON.parse(data.SecretString);
    const accountSid = secrets.TWILIO_ACCOUNT_SID;
    const authToken = secrets.TWILIO_AUTH_TOKEN;
    const twilioNumber = secrets.TWILIO_PHONE_NUMBER;

    if (accountSid && authToken && twilioNumber) {
        //Create a Twilio Client
        const client = new Twilio(accountSid, authToken);
        //Loop into al records of the event, every record is every message sent from Sqs
        for (const record of event.Records) {
            const body = JSON.parse(record.body);
            const userNumber = "+" + body.number;
            //SendMessage function
            try {
                const message = client.messages.create({
                    from: twilioNumber,
                    to: userNumber,
                    body: body.message,
                });
                return message;
            } catch (error) {
                return `Failed to send sms message. Error Code: ${error.errorCode} / Error Message: ${error.errorMessage}`;
            }
        }
    } else {
        return "You are missing one of the variables you need to send a message";
    }
}

The I call this function from my index:我从我的索引中称之为 function:

import { SQSEvent } from "aws-lambda";
import { sendSms } from "./services/sendSms/sendSms";
import { getSecret } from "./services/obtainSecrets/getSecret";
import { SecretsManager } from "aws-sdk";

export const lambdaHandler = async (event: SQSEvent) => {
    try {
        const obtainedSecret = await getSecret()
            .then((credentials: SecretsManager.GetSecretValueResponse) => {
                return credentials;
            })
            .catch(error => {
                return error;
            });
        const response = sendSms(event, obtainedSecret)
            .then(response => {
                return response;
            })
            .catch(error => {
                return error;
            });
        return {
            message: "OK " + obtainedSecret + response,
            code: 200,
        };
    } catch (error) {
        throw new Error(error);
    }
};

I have already make some tests, but them always makes a connection with Twilio api(requiring the real token, sid,etc), and I need to mock the Twilio service, so the function I call in my test.ts doesn't connects to internet.我已经进行了一些测试,但它们总是与 Twilio api 建立连接(需要真正的令牌、sid 等),并且我需要模拟 Twilio 服务,因此 ZC1C425268E68385D1AB5ZI074C 连接测试。到互联网。

I have tried this so far:到目前为止,我已经尝试过:

I tried to mock the Twilio library and my sendSms service.我试图模拟 Twilio 库和我的 sendSms 服务。

I have created a smsMessageResultMock to simulate a success response of sendSms.我创建了一个 smsMessageResultMock 来模拟 sendSms 的成功响应。

Then I update that smsMessageResultMock to simulate a failed response.然后我更新该 smsMessageResultMock 以模拟失败的响应。

Then I tried to create a client with mocked Twilio, so I can call the Twilio's messages.create to send a message and give it a jest.fn().mockResolvedValue({...smsMessageresultMock}).然后我尝试使用模拟的 Twilio 创建一个客户端,所以我可以调用 Twilio 的 messages.create 来发送消息并给它一个 jest.fn().mockResolvedValue({...smsMessageresultMock})。

At last, I expect that when I call the function sendSms(event,data) to throw an error and that error will be Failed to send sms message. Error Code: ${smsMessageMock.errorCode} / Error Message: ${smsMessageMock.errorMessage}最后,我希望当我调用 function sendSms(event,data) 时抛出一个错误,该错误将是Failed to send sms message. Error Code: ${smsMessageMock.errorCode} / Error Message: ${smsMessageMock.errorMessage} Failed to send sms message. Error Code: ${smsMessageMock.errorCode} / Error Message: ${smsMessageMock.errorMessage}

import { Twilio } from "twilio";
import { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
import { sendSms } from "../../services/sendSms/sendSms";

//mock Twilio library and sendSms service
jest.mock("twilio");
jest.mock("../../services/sendSms/sendSms");

const smsMessageResultMock: Partial<MessageInstance> = {
    status: "sent",
    sid: "AC-lorem-ipsum",
    errorCode: undefined,
    errorMessage: undefined,
};
describe("SMS Service", () => {
    describe("Send Message", () => {
        it("Should fail", async () => {
            // update smsMessageResultMock to simulate a faled response
            const smsMessageMock = {
                ...smsMessageResultMock,
                status: "failed",
                errorCode: 123,
                errorMessage: "lorem-ipsum",
            };
            // simulated response of secret management
            let data = {
                ARN: "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3",
                Name: "MyTestDatabaseSecret",
                SecretString:
                    '{"TWILIO_ACCOUNT_SID": "ACTWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN": "TWILIO_AUTH_TOKEN","TWILIO_PHONE_NUMBER": "TWILIO_PHONE_NUMBER"}',
                VersionId: "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1",
                VersionStages: ["AWSPREVIOUS"],
            };
            // simulated response of SqsEvent
            let event = {
                Records: [
                    {
                        messageId: "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
                        receiptHandle: "MessageReceiptHandle",
                        body: '{"message": "Hello world","number": "(506)88888888"}',
                        attributes: {
                            ApproximateReceiveCount: "1",
                            SentTimestamp: "1523232000000",
                            SenderId: "123456789012",
                            ApproximateFirstReceiveTimestamp: "1523232000001",
                        },
                        messageAttributes: {},
                        md5OfBody: "{{{md5_of_body}}}",
                        eventSource: "aws:sqs",
                        eventSourceARN: "arn:aws:sqs:us-east-1:123456789012:MyQueue",
                        awsRegion: "us-east-1",
                    },
                ],
            };
            // simulate tokens for Twilio
            const accountSid = "ACfjhdskjfhdsiuy876hfijhfiudsh";
            const authToken = "fjfuewfiuewfbodfiudfgifasdsad";
            //create client with mocked Twilio
            const client = new Twilio(accountSid, authToken);

            //call messages.create of Twilio client, and give it the expected result created
            client.messages.create = jest
                .fn()
                .mockResolvedValue({ ...smsMessageMock });

            console.log(await sendSms(event, data));
            //expectes the function sendSms(event, data) to throw an error
            await expect(sendSms(event, data)).rejects.toThrowError(
                `Failed to send sms message. Error Code: ${smsMessageMock.errorCode} / Error Message: ${smsMessageMock.errorMessage}`
            );
        });
    });
});

(event and data are simulated responses of SqsEvent and GetSecretValueResponse) (事件和数据是 SqsEvent 和 GetSecretValueResponse 的模拟响应)

The problem is that when I run the npm test it throws me an error of Twilio's authentication, an it is because I'm passing self created tokens.问题是,当我运行 npm 测试时,它会抛出 Twilio 身份验证错误,这是因为我正在传递自创令牌。

 Expected substring: "Failed to send sms message. Error Code: 123 / Error Message: lorem-ipsum"                                             
    Received message:   "Authentication Error - invalid username"                                                                              
                                                                                                                                               
          at success (node_modules/twilio/lib/base/Version.js:135:15)                                                                          
          at Promise_then_fulfilled (node_modules/q/q.js:766:44)                                                                               
          at Promise_done_fulfilled (node_modules/q/q.js:835:31)                                                                               
          at Fulfilled_dispatch [as dispatch] (node_modules/q/q.js:1229:9)
          at Pending_become_eachMessage_task (node_modules/q/q.js:1369:30)
          at RawTask.Object.<anonymous>.RawTask.call (node_modules/asap/asap.js:40:19)
          at flush (node_modules/asap/raw.js:50:29)

So what I suppose is that the test is connecting to internet and calling Twilio's api.所以我认为测试是连接到互联网并调用 Twilio 的 api。

I appreciate if you could help me.如果您能帮助我,我将不胜感激。

Edit, Im using SQS to get the number and the body of the message, and I get Twilio Token and Sid from Secret Management.编辑,我使用 SQS 获取消息的编号和正文,并从 Secret Management 获取 Twilio 令牌和 Sid。 I'm really new in unit testing, I have tried a lot, but I can't get it我在单元测试方面真的很新,我尝试了很多,但我无法得到它

I think what you want to do is mock the class returned by the module, using jest.mock('twilio', mockImplementation) and in mockImplementation return a function to act as a constructor that will take your account SID and auth token arguments and then return a mockClient implementation, which in this case needs to return an object which has a messages property, which in turn is an object with a create property that is a mock function. I think what you want to do is mock the class returned by the module, using jest.mock('twilio', mockImplementation) and in mockImplementation return a function to act as a constructor that will take your account SID and auth token arguments and then返回一个mockClient实现,在这种情况下需要返回一个具有messages属性的 object,它又是一个 object,其create属性是一个模拟 function。

It's probably easier to just show the code.只显示代码可能更容易。

const mockClient = {
  messages: {
    create: jest.fn().mockResolvedValue({ ...smsMessageMock });
  }
};

jest.mock("twilio", () => {
  return function(accountSid, authToken) {
    return mockClient;
  }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM