测试js模块Promise.all

时间:2019-07-07 17:02:25

标签: javascript jestjs

我如何测试此javascript模块代码,我的测试通过了,但是甚至无法涵盖Promise.all或anycode(尝试一次执行一个步骤),我已经尝试过此操作(请检查图片以了解覆盖范围):< / p>

How to set a test for multiple fetches with Promise.all using jest

enter image description here

const dbSession = require("server/db/dbSessionModule");
jest.mock("server/db/dbSessionModule");

let controller = {
    post: (request, response) => {
        const dbSession = new dbSessionModule();
        const httpResponse = new HttpResponse();

        Promise.all([
            bcrypt.hash(request.body.payload.password, config.saltRounds),
            dbSession.connect()
        ])
            .then((promiseValues) => {
                return signupModule.createAccount(dbSession, request.body.payload, promiseValues[0]);
            })
            .then((responsePayload) => {
                httpResponse.setSuccess(201, "ACCOUNT_CREATED", responsePayload);
                response.status(httpResponse.status).json(httpResponse);
            })
            .catch(error => {
                console.log(error);
                httpResponse.setReject(500, "ACCOUNT_CREATION_ERROR", error);
                response.status(httpResponse.status).json(httpResponse);
            })
            .finally(() => {
                dbSession.release();
            })
    }
}

my version:

describe("Signup Controller", function () {

    it("Should hash password and connect user", () => {
        const passowrd = "test";
        const hashPassword = "3rasf4#4ad$@!";

        const bcrypt = {
            hash: jest.fn().mockImplementation(function () {
                return Promise.resolve(hashPassword);
            })
        }

        return expect(
            Promise.all([
                bcrypt.hash(passowrd, 5),
                dbSession.connect()
            ])
        )
            .resolves
            .toEqual([hashPassword, {}])
    });
})

1 个答案:

答案 0 :(得分:0)

这是解决方案,我模拟导入的模块,目录结构为:

.
├── HttpResponse.ts
├── bcrypt.ts
├── config.ts
├── dbSessionModule.ts
├── index.spec.ts
├── index.ts
└── signupModule.ts

index.ts,将对文件进行测试

import HttpResponse from './HttpResponse';
import DbSessionModule from './dbSessionModule';
import bcrypt from './bcrypt';
import signupModule from './signupModule';
import config from './config';

const controller = {
  post: (request, response) => {
    const dbSession = new DbSessionModule();
    const httpResponse = new HttpResponse();

    return Promise.all([bcrypt.hash(request.body.payload.password, config.saltRounds), dbSession.connect()])
      .then(promiseValues => {
        return signupModule.createAccount(dbSession, request.body.payload, promiseValues[0]);
      })
      .then(responsePayload => {
        httpResponse.setSuccess(201, 'ACCOUNT_CREATED', responsePayload);
        response.status(httpResponse.status).json(httpResponse);
      })
      .catch(error => {
        console.log(error);
        httpResponse.setReject(500, 'ACCOUNT_CREATION_ERROR', error);
        response.status(httpResponse.status).json(httpResponse);
      })
      .finally(() => {
        dbSession.release();
      });
  }
};

export default controller;

单元测试index.spec.ts

import '@babel/polyfill';

import controller from './';
import DbSessionModule from './dbSessionModule';
import bcrypt from './bcrypt';
import signupModule from './signupModule';
import config from './config';
import HttpResponse from './HttpResponse';

const request = {
  body: {
    payload: {
      password: ''
    }
  }
};
const response = {
  status: jest.fn().mockReturnThis(),
  json: jest.fn().mockReturnThis()
};

const HttpResponseMocked = {
  setSuccess: jest.fn().mockImplementation(status => {
    HttpResponseMocked.status = status;
  }),
  setReject: jest.fn().mockImplementation(status => {
    HttpResponseMocked.status = status;
  }),
  status: 0
};

jest.mock('./HttpResponse.ts', () => {
  return jest.fn(() => HttpResponseMocked);
});

jest.mock('./bcrypt.ts');

const DbSessionModuleMocked = {
  connect: jest.fn(),
  release: jest.fn()
};

jest.mock('./dbSessionModule.ts', () => {
  return jest.fn(() => DbSessionModuleMocked);
});

jest.mock('./signupModule.ts');

const dbSessionModule = new DbSessionModule();
const httpResponse = new HttpResponse();

describe('controller', () => {
  describe('#post', () => {
    request.body.payload.password = '123';
    config.saltRounds = 'mocked salt';

    beforeEach(() => {
      (dbSessionModule as jest.Mocked<DbSessionModule>).connect.mockReset();
      (dbSessionModule as jest.Mocked<DbSessionModule>).release.mockReset();
    });
    it('create account correctly', async () => {
      (bcrypt as jest.Mocked<typeof bcrypt>).hash.mockResolvedValueOnce('mocked hash');
      (dbSessionModule as jest.Mocked<DbSessionModule>).connect.mockResolvedValueOnce({});
      (signupModule as jest.Mocked<typeof signupModule>).createAccount.mockResolvedValueOnce({ accountId: 1 });

      await controller.post(request, response);

      expect(bcrypt.hash).toBeCalledWith('123', 'mocked salt');
      expect(dbSessionModule.connect).toBeCalledTimes(1);
      expect(signupModule.createAccount).toBeCalledWith(dbSessionModule, { password: '123' }, 'mocked hash');
      expect(httpResponse.setSuccess).toBeCalledWith(201, 'ACCOUNT_CREATED', { accountId: 1 });
      expect(response.status).toBeCalledWith(201);
      expect(response.json).toBeCalledWith(httpResponse);
      expect(dbSessionModule.release).toBeCalledTimes(1);
    });

    it('create account error', async () => {
      (bcrypt as jest.Mocked<typeof bcrypt>).hash.mockResolvedValueOnce('mocked hash');
      (dbSessionModule as jest.Mocked<DbSessionModule>).connect.mockResolvedValueOnce({});
      (signupModule as jest.Mocked<typeof signupModule>).createAccount.mockRejectedValueOnce(new Error('some error'));

      await controller.post(request, response);

      expect(bcrypt.hash).toBeCalledWith('123', 'mocked salt');
      expect(dbSessionModule.connect).toBeCalledTimes(1);
      expect(signupModule.createAccount).toBeCalledWith(dbSessionModule, { password: '123' }, 'mocked hash');
      expect(httpResponse.setReject).toBeCalledWith(500, 'ACCOUNT_CREATION_ERROR', new Error('some error'));
      expect(response.status).toBeCalledWith(500);
      expect(response.json).toBeCalledWith(httpResponse);
      expect(dbSessionModule.release).toBeCalledTimes(1);
    });
  });
});

单元测试结果和覆盖范围:

 PASS  src/stackoverflow/56924299/index.spec.ts
  controller
    #post
      ✓ create account correctly (10ms)
      ✓ create account error (8ms)

  console.log src/stackoverflow/56924299/index.ts:595
    Error: some error
        at Object.<anonymous> (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/56924299/index.spec.ts:80:94)
        at step (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/56924299/index.spec.ts:32:23)
        at Object.next (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/56924299/index.spec.ts:13:53)
        at /Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/56924299/index.spec.ts:7:71
        at new Promise (<anonymous>)
        at Object.<anonymous>.__awaiter (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/56924299/index.spec.ts:3:12)
        at Object.<anonymous> (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/56924299/index.spec.ts:77:32)
        at Object.asyncJestTest (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at resolve (/Users/elsa/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>)

-----------------|----------|----------|----------|----------|-------------------|
File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files        |    85.19 |      100 |    71.43 |    85.19 |                   |
 bcrypt.ts       |       50 |      100 |        0 |       50 |               2,3 |
 config.ts       |      100 |      100 |      100 |      100 |                   |
 index.ts        |      100 |      100 |      100 |      100 |                   |
 signupModule.ts |       50 |      100 |        0 |       50 |               2,3 |
-----------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.414s, estimated 3s

完整的代码演示在这里:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/56924299

测试覆盖率报告:

enter image description here