【问题标题】:Jest mock class methodsJest 模拟类方法
【发布时间】:2021-12-08 11:21:17
【问题描述】:

我有这门课:

class DataService {
    constructor() {
    }

    async CreateItem() {
        try {
            return {data: true, error: null}
        } catch (error) {
            return {data: null, error: error}
        }
    }

    async SendToAnalytics() {
        try {
            return {data: true, error: null}
        } catch (error) {
            return {data: null, error: error}
        }
    }
    async SendEmail() {
        try {
            return {data: true, error: null}
        } catch (error) {
            return {data: null, error: error}
        }
    }

   
}

module.exports = DataService;

我在我的 Lambda 处理程序中调用这些方法:

const DataService = require("../services/data.service");

exports.handler = async (event) => {
  try {
    const dataService = new DataService();
    const createItem = await dataService.CreateItem();
    if (createItem.error) {
      return {statusCode: 500};
    }
    const sendToAnalytics = await dataService.SendToAnalytics();
    if (sendToAnalytics.error) {
      return {statusCode: 500};
    }
    const sendEmail = await dataService.SendEmail();
    if (sendEmail.error) {
      return {statusCode: 500};
    }
    return {statusCode: 200};
  } catch (e) {
    return {statusCode: 500};
  }
};

我想覆盖 100% 的代码,这是我的 handler.spec 文件

const { handler } = require("./handler");
const DataService = require("../services/data.service");

jest.mock("../services/data.service", () => {
  return jest.fn().mockImplementation(() => {
    return {
      CreateItem: jest.fn(() => ({ data: true, error: null })),
      SendToAnalytics: jest.fn(() => ({ data: true, error: null })),
      SendEmail: jest.fn(() => ({ data: true, error: null })),
    };
  });
});

const dataService = new DataService();

describe("Job Apply Handler", () => {
  afterAll(() => {
    jest.resetAllMocks();
  });
  it("Successful response", async () => {
    const res = await handler();
    expect(res.statusCode).toEqual(200);
  });
  it("Error Response because of CreateItem Error", async () => {
    dataService.SaveApplicant.mockImplementationOnce(
      jest.fn(() => ({ data: null, error: true }))
    );
    const res = await handler();
    expect(res.statusCode).toEqual(500);
  });
  it("Error Response because of SendToAnalytics Error", async () => {
    dataService.SendToAnalytics.mockImplementationOnce(
      jest.fn(() => ({ data: null, error: true }))
    );
    //DOES NOT ENTER inside if(sendToAnalyticsError)
    // CreateItem is still mocked to return error: true
    const res = await handler();
    expect(res.statusCode).toEqual(500);
  });
  it("Error Response because of SendEmail Error", async () => {
    dataService.SendToAnalytics.mockImplementationOnce(
      jest.fn(() => ({ data: null, error: true }))
    );
    //DOES NOT ENTER inside if(sendEmail.error)
    // CreateItem is still mocked to return error: true
    const res = await handler();
    expect(res.statusCode).toEqual(500);
  });
  it("Error Response because of Exception", async () => {
    dataService.SendToAnalytics.mockImplementationOnce(
      jest.fn(() => {
        throw new Error("error");
      })
    );
    const res = await handler();
    expect(res.statusCode).toEqual(500);
  });
});

我想我是在嘲笑错误的方法。由于在模拟返回错误后我无法重置 CreateItem(),所有其他情况都出现在第一个 IF 语句中。

有什么建议吗?

【问题讨论】:

    标签: javascript unit-testing jestjs mocking


    【解决方案1】:

    由于你使用async/await关键字,DataService中的CreateItemSendToAnalyticsSendEmail都是异步方法。

    您应该使用mockFn.mockResolvedValueOnce(value)mockFn.mockRejectedValueOnce(value) 模拟这些方法的已解决/拒绝值。

    例如

    data.serivce.js:

    class DataService {
      constructor() {}
    
      async CreateItem() {
        try {
          return { data: true, error: null };
        } catch (error) {
          return { data: null, error: error };
        }
      }
    
      async SendToAnalytics() {
        try {
          return { data: true, error: null };
        } catch (error) {
          return { data: null, error: error };
        }
      }
      async SendEmail() {
        try {
          return { data: true, error: null };
        } catch (error) {
          return { data: null, error: error };
        }
      }
    }
    
    module.exports = DataService;
    

    handler.js:

    const DataService = require('./data.service');
    
    exports.handler = async (event) => {
      try {
        const dataService = new DataService();
        const createItem = await dataService.CreateItem();
        if (createItem.error) {
          return { statusCode: 500 };
        }
        const sendToAnalytics = await dataService.SendToAnalytics();
        if (sendToAnalytics.error) {
          return { statusCode: 500 };
        }
        const sendEmail = await dataService.SendEmail();
        if (sendEmail.error) {
          return { statusCode: 500 };
        }
        return { statusCode: 200 };
      } catch (e) {
        return { statusCode: 500 };
      }
    };
    

    handler.test.js:

    const { handler } = require('./handler');
    
    const dataService = {
      CreateItem: jest.fn(() => ({ data: true, error: null })),
      SendToAnalytics: jest.fn(() => ({ data: true, error: null })),
      SendEmail: jest.fn(() => ({ data: true, error: null })),
    };
    jest.mock('./data.service', () => jest.fn(() => dataService));
    
    describe('Job Apply Handler', () => {
      afterAll(() => {
        jest.resetAllMocks();
      });
      it('Successful response', async () => {
        const res = await handler();
        expect(res.statusCode).toEqual(200);
      });
      it('Error Response because of CreateItem Error', async () => {
        dataService.CreateItem.mockResolvedValueOnce({ data: null, error: true });
        const res = await handler();
        expect(res.statusCode).toEqual(500);
      });
      it('Error Response because of SendToAnalytics Error', async () => {
        dataService.SendToAnalytics.mockResolvedValueOnce({ data: null, error: true });
        const res = await handler();
        expect(res.statusCode).toEqual(500);
      });
      it('Error Response because of SendEmail Error', async () => {
        dataService.SendToAnalytics.mockResolvedValueOnce({ data: null, error: true });
        const res = await handler();
        expect(res.statusCode).toEqual(500);
      });
      it('Error Response because of Exception', async () => {
        dataService.SendToAnalytics.mockRejectedValueOnce(new Error('error'));
        const res = await handler();
        expect(res.statusCode).toEqual(500);
      });
    });
    

    测试结果:

     PASS  examples/69666288/handler.test.js (9.639 s)
      Job Apply Handler
        ✓ Successful response (4 ms)
        ✓ Error Response because of CreateItem Error
        ✓ Error Response because of SendToAnalytics Error
        ✓ Error Response because of SendEmail Error (1 ms)
        ✓ Error Response because of Exception
    
    ------------|---------|----------|---------|---------|-------------------
    File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ------------|---------|----------|---------|---------|-------------------
    All files   |   93.75 |    83.33 |     100 |   93.33 |                   
     handler.js |   93.75 |    83.33 |     100 |   93.33 | 16                
    ------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       5 passed, 5 total
    Snapshots:   0 total
    Time:        10.795 s
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-07
      • 2020-06-21
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      • 2019-09-14
      • 1970-01-01
      相关资源
      最近更新 更多