0

这个项目是通过AWS Timestream来记录数据的,效果很好。

但是,我无法使用 jest 来模拟 AWS TimestreamWrite。我尝试了一些方法,但没有奏效。有人能帮我吗?

我的文件如下:

分类帐服务.js

const AWS = require("aws-sdk");
const enums = require("./enums");

var https = require("https");
var agent = new https.Agent({
  maxSockets: 5000,
});
const tsClient = new AWS.TimestreamWrite({
  maxRetries: 10,
  httpOptions: {
    timeout: 20000,
    agent: agent,
  },
});

module.exports = {
  log: async function (audit) {
    try {
      if (Object.keys(audit).length !== 0) {
        if (!isPresent(audit, "name")) {
          throw new Error("Name shouldn't be empty");
        }

        if (!isPresent(audit, "value")) {
          throw new Error("Value shouldn't be empty");
        }

        return await writeRecords(recordParams(audit));
      } else {
        throw new Error("Audit object is empty");
      }
    } catch (e) {
      throw new Error(e);
    }
  },
};
function isPresent(obj, key) {
  return obj[key] != undefined && obj[key] != null && obj[key] != "";
}
function recordParams(audit) {
  const currentTime = Date.now().toString(); // Unix time in milliseconds
  const dimensions = [
    // { Name: "client", Value: audit["clientId"] },
    { Name: "user", Value: audit["userId"] },
    { Name: "entity", Value: audit["entity"] },
    { Name: "action", Value: audit["action"] },
    { Name: "info", Value: audit["info"] },
  ];

  return {
    Dimensions: dimensions,
    MeasureName: audit["name"],
    MeasureValue: audit["value"],
    MeasureValueType: "VARCHAR",
    Time: currentTime.toString(),
  };
}
function writeRecords(records) {
  try {
    const params = {
      DatabaseName: enums.AUDIT_DB,
      TableName: enums.AUDIT_TABLE,
      Records: [records],
    };

    return tsClient.writeRecords(params).promise();
  } catch (e) {
    throw new Error(e);
  }
}

分类帐服务.spec.js

const AWS = require("aws-sdk");
const audit = require("./ledger-service");

describe("ledger-service", () => {

    beforeEach(async () => {
        jest.resetModules();
    });
  
    afterEach(async () => {
      jest.resetAllMocks();
    });

    it("It should write records when all success", async () => {
        const mockAudit={
            name: 'testName',
            value: 'testValue',
            userId: 'testUserId',
            entity: 'testEntity',
            action: 'testAction',
            info: 'testInfo',
        };

        const mockWriteRecords = jest.fn(() =>{
            console.log('mock success')
            return { promise: ()=> Promise.resolve()}
         });

        const mockTsClient={
            writeRecords: mockWriteRecords
        }

        jest.spyOn(AWS,'TimestreamWrite');
        AWS.TimestreamWrite.mockImplementation(()=>mockTsClient);

        //a=new AWS.TimestreamWrite();
        //a.writeRecords();   //these two lines will pass the test and print "mock success"

        await audit.log(mockAudit); //this line will show "ConfigError: Missing region in config"

        expect(mockWriteRecords).toHaveBeenCalled();
    });
});

我只是认为我嘲笑的 AWS 没有传递到ledger-service.js. 有没有办法解决这个问题?

谢谢

更新:采纳 hoangdv 的建议

我在想jest.resetModules(); jest.resetAllMocks();不工作。如果我将“它应该在所有成功时写入记录”作为第一个测试,它将通过测试。但是,如果前面有一个,它将失败。

经过

  it("It should write records when all success", async () => {
    const mockAudit = {
      name: 'testName',
      value: 'testValue',
      userId: 'testUserId',
      entity: 'testEntity',
      action: 'testAction',
      info: 'testInfo',
    };

    await audit.log(mockAudit);

    expect(AWS.TimestreamWrite).toHaveBeenCalledWith({
      maxRetries: 10,
      httpOptions: {
        timeout: 20000,
        agent: expect.any(Object),
      },
    });
    expect(mockWriteRecords).toHaveBeenCalled();
  });

  it("It should throw error when audit is empty", async () => {
    const mockAudit = {};

    await expect(audit.log(mockAudit)).rejects.toThrow(`Audit object is empty`);
  });

失败的

  it("It should throw error when audit is empty", async () => {
    const mockAudit = {};

    await expect(audit.log(mockAudit)).rejects.toThrow(`Audit object is empty`);
  });

  it("It should write records when all success", async () => {
    const mockAudit = {
      name: 'testName',
      value: 'testValue',
      userId: 'testUserId',
      entity: 'testEntity',
      action: 'testAction',
      info: 'testInfo',
    };

    await audit.log(mockAudit);

    expect(AWS.TimestreamWrite).toHaveBeenCalledWith({
      maxRetries: 10,
      httpOptions: {
        timeout: 20000,
        agent: expect.any(Object),
      },
    });
    expect(mockWriteRecords).toHaveBeenCalled();
  });
4

1 回答 1

0

ledger-service.js您调用new AWS.TimestreamWrite“之前”module.exports时,这意味着它将使用实际逻辑而不是模拟来调用它。

AWS在您致电之前,解决方案只是模拟require("./ledger-service");

分类帐服务.spec.js

const AWS = require("aws-sdk");

describe("ledger-service", () => {
  let audit;
  let mockWriteRecords;

  beforeEach(() => {
    mockWriteRecords = jest.fn(() => {
      return { promise: () => Promise.resolve() }
    });

    jest.spyOn(AWS, 'TimestreamWrite');
    AWS.TimestreamWrite.mockImplementation(() => ({
      writeRecords: mockWriteRecords
    }));

    audit = require("./ledger-service"); // this line
  });

  afterEach(() => {
    jest.resetModules(); // reset module to update change for each require call
    jest.resetAllMocks();
  });

  it("It should write records when all success", async () => {
    const mockAudit = {
      name: 'testName',
      value: 'testValue',
      userId: 'testUserId',
      entity: 'testEntity',
      action: 'testAction',
      info: 'testInfo',
    };

    await audit.log(mockAudit);

    expect(AWS.TimestreamWrite).toHaveBeenCalledWith({
      maxRetries: 10,
      httpOptions: {
        timeout: 20000,
        agent: expect.any(Object),
      },
    });
    expect(mockWriteRecords).toHaveBeenCalled();
  });
});

于 2021-05-07T02:38:13.253 回答