如何测试使用Jest调用API的函数?

时间:2020-11-08 09:46:01

标签: node.js unit-testing jestjs

我是Jest的Node.js单元测试的新手,并且还在学习中。我想知道单元测试调用API的函数的正确方法是什么?目前,我正在使用跨取库进行API调用。我想实现有效负载验证,API调用上的2xx和5xx API响应的单元测试。

这是我的代码:

export const myFunction = (payload: any) => {
  if (_.isNull(payload) || _.isUndefined(payload)) {
    throw new Error('payload is required')
  }

  httpFetch('http://localhost/api/send', { method: 'POST' }, { 'content-type': 'application/json', Authorization: 'Bearer 12ABC'})
    .then((resp) => {
      // ...return 2xx
    })
    .catch((e) => {
       // ...return 5xx
    })
}

2 个答案:

答案 0 :(得分:0)

有两种方法可以做到这一点:

模拟或伪造API调用并输出伪造的响应(错误或其他)


httpFetch = jest.fn(()=>Promise.resolve("provide-dummy-response-payload"));

httpFetch = jest.fn(()=>Promise.reject("provide-dummy-error-payload"));

现在,您可以在类似的测试中使用该模拟了:

// pseudo code

  it("makes the api call successfully",async ()=>{
     httpFetch = jest.fn(()=>Promise.resolve("provide-dummy-response-payload"));
     const result = await myFunction("random-payload");
     // make assertions about the result here
  });

  it("fails the api call",async ()=>{
     httpFetch = jest.fn(()=>Promise.reject("provide-dummy-error-payload"));
     const error = await myFunction("random-payload");
     // make assertions about error here
  });

(2)通过故意传递正确和不正确的有效负载并匹配预期结果来进行api调用

在这种情况下,您将需要知道如何使API调用失败或失败。

因此,如果有效载荷不包含某个属性或属性类型不正确,您的API可能会失败。

这种方法取决于您提供给函数的有效载荷。

答案 1 :(得分:0)

广泛地有两种(不是互斥的)单元测试*这样的功能:

  1. 隔离测试,用test doubles替换协作者:

    import httpFetch from "wherever";
    
    import myFunction from "somewhere";
    
    jest.mock("wherever");
    
    describe("myFunction", () => {
      it("calls httpFetch", async () => {
        httpFetch.mockResolvedValue();
    
        await myFunction({});
    
        expect(httpFetch).toHaveBeenCalledWith(
          "http://localhost/api/send",
          { method: "POST" },
          { "Content-Type": "application/json", Authorization: "Bearer 12ABC" }
        );
      });
    });
    

    这是“最简单”的方法,但是现在您已经连接到httpFetch接口,这违反了规则“不要嘲笑您不拥有的东西” -如果该库的界面在某个时候发生了变化,这些测试不会告诉您。

  2. 集成测试,使用Nock之类的东西检查传输层发生的情况:

    import nock from "nock";
    
    import myFunction from "somewhere";
    
    describe("myFunction", async () => {
      it("makes the right request", () => {
        const scope = nock("http://localhost/api", {
          reqheaders: {
            "Content-Type": "application/json",
            Authorization: "Bearer 12ABC",
          },
        })
          .post("/send")
          .reply(201);
    
        await myFunction({});
    
        scope.done();
      });
    });
    

    这需要更多的设置,但是意味着您与httpFetch界面的耦合更少-例如,您可以升级该库或切换到另一个库,但仍然可以确信一切正常。

还有其他方法可以与特定库的接口分离;例如,您可以围绕它编写一个 facade 并对其进行模拟。但是您仍然想知道正在发出正确的请求,并且出于与以前相同的原因,您不应该针对库的测试倍数来测试外观。

您可能还会进行更高级别的测试,例如E2E针对真实的后端进行测试,或针对其后端进行合约测试;这将影响您希望如何平衡较低级别测试的数量和类型。总体而言,这些选项如下所示:

System:      [Service] -> [Library] -> [HTTP] -> [Backend]

Isolated:    |<----->| -> (Test Double)

Integration: |<------------------>| -> (Nock)

Contract:    |<---------------------------->| -> (Stub)

E2E:         |<----------------------------------------->|

请记住,目标(或one of them)是要确保您正在编写的代码能够正常工作,如果情况不再如此,您将以有助于您解决问题的方式迅速找到答案。

* 围绕“单元测试”的内容有很多想法。考虑到速度,独立性和并行性的原理,我在此上下文中使用的定义是:实际上没有发出网络请求的测试。