Jest:如何在我的代码

时间:2017-12-01 05:48:53

标签: node.js mocking jest

我的ES6 User类中有以下功能,用于搜索给定字符串的用户。

// Search for a user by their pNick, includes partial matching
    static getBypNick(pNick = '') {
        // Define our search criteria regex and normalise to lower case
        const userSearchRegex = new RegExp(`^${pNick.toLowerCase()}`, 'i')

        return new Promise((resolve, reject) => {

            // Search user collection for pNick using regex like search and return array of results
            userTable.find({
                _pNick: userSearchRegex
            }).sort({
                _pNick: 1
            }).exec(function (err, result) {

                // If error reject
                if (err) {
                    return reject(err)
                }
                const userArray = result.map((user) => {
                    return new User(
                        user._pNick,
                        user._firstName,
                        user._userName,
                        user._phoneNumber,
                        user._userID)
                })
                // Return user records if found
                return resolve(userArray)
            })
        })
    }

虽然我可以使用Jest轻松测试成功路由,但我很难理解如何调用错误情况,特别是在函数中的.exec方法中调用promise中的拒绝路由。

我知道我可以使用各种Jest功能,例如mockImplementation,但我无法弄清楚这种情况下的最佳情况。在幕后使用的数据库是NeDB,我非常肯定我只需要强制.exec部分返回错误然后我应该在我的承诺中捕获它。

我无意测试底层的NeDB库,因为它有自己的测试成功执行,所以这完全是我自己的方法。

到目前为止我的报道: Code Coverage

1 个答案:

答案 0 :(得分:0)

这是单元测试解决方案:

userRepo.js

import { userTable } from './userTable';
import { User } from './user';

export class UserRepo {
  static getBypNick(pNick = '') {
    const userSearchRegex = new RegExp(`^${pNick.toLowerCase()}`, 'i');

    return new Promise((resolve, reject) => {
      userTable
        .find({
          _pNick: userSearchRegex,
        })
        .sort({
          _pNick: 1,
        })
        .exec(function(err, result) {
          if (err) {
            return reject(err);
          }
          const userArray = result.map((user) => {
            return new User(user._pNick, user._firstName, user._userName, user._phoneNumber, user._userID);
          });
          return resolve(userArray);
        });
    });
  }
}

userTable.js

const userTable = {
  find() {
    return this;
  },
  sort() {
    return this;
  },
  exec(fn) {
    console.log('real exec');
    fn();
  },
};

user.js

export class User {
  constructor(nick, firstName, userName, phoneNumber, userId) {
    this.nick = nick;
    this.firstName = firstName;
    this.userName = userName;
    this.phoneNumber = phoneNumber;
    this.userId = userId;
  }
}

userRepo.test.js

import { UserRepo } from './userRepo';
import { userTable } from './userTable';

jest.mock('./userTable', () => {
  const mUserTable = {
    find: jest.fn().mockReturnThis(),
    sort: jest.fn().mockReturnThis(),
    exec: jest.fn(),
  };
  return { userTable: mUserTable };
});

describe('47587358', () => {
  afterAll(() => {
    jest.resetAllMocks();
  });
  it('should get user by nick', async () => {
    const mResult = [{ _pNick: '_pNick', _firstName: '_firstName', _userName: '_userName', _phoneNumber: 123456, _userID: 1 }];
    userTable.exec.mockImplementationOnce((fn) => {
      fn(null, mResult);
    });
    const actual = await UserRepo.getBypNick('jest');
    expect(actual).toEqual(
      expect.arrayContaining([
        expect.objectContaining({
          nick: expect.any(String),
          firstName: expect.any(String),
          userName: expect.any(String),
          phoneNumber: expect.any(Number),
          userId: expect.any(Number),
        }),
      ]),
    );
    expect(userTable.find).toBeCalledWith({ _pNick: new RegExp(`^jest`, 'i') });
    expect(userTable.sort).toBeCalledWith({ _pNick: 1 });
    expect(userTable.exec).toBeCalledWith(expect.any(Function));
  });

  it('should handle error', async () => {
    const mError = new Error('network');
    userTable.exec.mockImplementationOnce((fn) => {
      fn(mError, null);
    });
    await expect(UserRepo.getBypNick('jest')).rejects.toThrowError('network');
    expect(userTable.find).toBeCalledWith({ _pNick: new RegExp(`^jest`, 'i') });
    expect(userTable.sort).toBeCalledWith({ _pNick: 1 });
    expect(userTable.exec).toBeCalledWith(expect.any(Function));
  });
});

具有覆盖率报告的单元测试结果:

 PASS  src/stackoverflow/47587358/userRepo.test.js (9.448s)
  47587358
    ✓ should get user by nick (10ms)
    ✓ should handle error (3ms)

-------------|----------|----------|----------|----------|-------------------|
File         |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------|----------|----------|----------|----------|-------------------|
All files    |      100 |    66.67 |      100 |      100 |                   |
 user.js     |      100 |      100 |      100 |      100 |                   |
 userRepo.js |      100 |    66.67 |      100 |      100 |                 5 |
-------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        10.66s

enter image description here

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47587358