测试框架Jest

本文全部资料请参考:github.com/antgod/reac…html

测试框架Jest

1. 快速开始

安装jest

npm install --save-dev jest复制代码

咱们先写一个测试函数,有两个数字参数作加法,首先,建立sum.js文件node

function sum(a, b) {
  return a + b
}
module.exports = sum复制代码

而后,建立建立sum.test.js,包含咱们目前的测试代码。react

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});复制代码

而后添加片断到package.json中android

{
  "scripts": {
    "test": "jest"
  }
}复制代码

最后运行npm test,jest输入以下内容webpack

PASS  ./sum.test.js
✓ adds 1 + 2 to equal 3 (5ms)复制代码

你刚刚成功的编写了一个jest测试!git

这个测试用例使用了expecttoBe进行两个值相同的测试。想要学习更多的关于jest测试,请参考 Using Matcherses6

从命令行运行

你也能够直接从命令行执行,能够输入一些有空的参数(npm install jest -g)。github

Here's how to run Jest on files matching my-test, using config.json as a configuration file and display a native OS notification after the run:web

jest my-test --notify --config=config.json复制代码

若是你想学习更多的命令行执行,请参考 Jest CLI Options正则表达式

附加配置

使用 Babel:
安装babel-jestregenerator-runtime 包:

npm install --save-dev babel-jest regenerator-runtime复制代码

注意: 若是你使用npm 3或者npm 4,你不用指明安装regenerator-runtime

添加一份.babelrc文件到你的工程根目录,好比,若是你使用es6或者react.js须要使用babel-preset-es2015babel-preset-react预设:

{
  "presets": ["es2015", "react"]
}复制代码

这样你会使用es6与react全部指定的语法。

注意: 若是你使用更多的babel编译配置,请使用babel's env option,记住jest将会自动定义node_env做为测试。

使用webpack

jest能够实用在工程内使用webpack管理你的资产,样式和编辑。webpack 提供一些特别的功能相比于其余工具。更多资料请参考 webpack guide

2. 使用匹配

普通匹配

jest使用matchers让你经过不一样的方法测试值。你须要熟记不少不一样的matchers。这里只介绍最经常使用的matchers

最简单的测试值相等的是精确相等:

test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});复制代码

上段代码,expect(2 + 2)返回一个“期待”对象。除了调用matchers,关于期待对象你不须要作太多。在这段代码中,.toBe(4)是一个matcher。当jest运行时,将追踪全部失败的matchers,因此它能够精确的打印错误信息。

toBe使用===精确等于测试。若是你想深度测试对象相等,使用toEqual代替。

test('object assignment', () => {
  const data = {one: 1};
  data['two'] = 2;
  expect(data).toEqual({one: 1, two: 2});
});复制代码

toEqual 递归的查找每一个字段对比是否相等。

你可使用not去测试matcher的反面:

test('adding positive numbers is not zero', () => {
  for (let a = 1; a < 10; a++) {
    for (let b = 1; b < 10; b++) {
      expect(a + b).not.toBe(0);
    }
  }
});复制代码

类型判断

有时候你须要判断undefined,null与false,但有时候你不须要明确的区分他们。jest包含工具明确的区分他们。

  • toBeNull matches only null
  • toBeUndefined matches only undefined
  • toBeDefined is the opposite of toBeUndefined
  • toBeTruthy matches anything that an if statement treats as true
  • toBeFalsy matches anything that an if statement treats as false

举个例子:

test('null', () => {
  const n = null;
  expect(n).toBeNull();
  expect(n).toBeDefined();
  expect(n).not.toBeUndefined();
  expect(n).not.toBeTruthy();
  expect(n).toBeFalsy();
});

test('zero', () => {
  const z = 0;
  expect(z).not.toBeNull();
  expect(z).toBeDefined();
  expect(z).not.toBeUndefined();
  expect(z).not.toBeTruthy();
  expect(z).toBeFalsy();
});复制代码

你可使用这些matcher作精确的匹配。

数字

多种途径比较数字

test('two plus two', () => {
  const value = 2 + 2;
  expect(value).toBeGreaterThan(3);
  expect(value).toBeGreaterThanOrEqual(3.5);
  expect(value).toBeLessThan(5);
  expect(value).toBeLessThanOrEqual(4.5);

  // toBe and toEqual are equivalent for numbers
  expect(value).toBe(4);
  expect(value).toEqual(4);
});复制代码

你可使用toBeCloseTo进行浮点比较

test('adding floating point numbers', () => {
  const value = 0.1 + 0.2;
  expect(value).not.toBe(0.3);    // 浮点数不会直接相等
  expect(value).toBeCloseTo(0.3); // 使用closeTo方法进行浮点数字比较
});复制代码

字符串

你可使用toMatch测试正则表达式来验证string字符串

test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);
});

test('but there is a "stop" in Christoph', () => {
  expect('Christoph').toMatch(/stop/);
});复制代码

数组

你能够检验数组是否包含某一个特别项

const shoppingList = [
  'diapers',
  'kleenex',
  'trash bags',
  'paper towels',
  'beer',
];

test('the shopping list has beer on it', () => {
  expect(shoppingList).toContain('beer');
});复制代码

表达式

你可使用toThrow来检验函数是否抛出异常

function compileAndroidCode() {
  throw new ConfigError('you are using the wrong JDK');
}

test('compiling android goes as expected', () => {
  expect(compileAndroidCode).toThrow();
  expect(compileAndroidCode).toThrow(ConfigError);

  // You can also use the exact error message or a regexp
  expect(compileAndroidCode).toThrow('you are using the wrong JDK');
  expect(compileAndroidCode).toThrow(/JDK/);
});复制代码

更多

这是一个just尝试,查看完整的matchers列表renerence docs

一旦你掌握了一个可用的matcher,建议下一步学习jest如何检验异步代码

3.测试异步代码

js运行异步代码是很广泛的。jest须要知道何时代码测试已完成,才能移动到下一个测试。jest有几种方法处理。

Callbacks

最广泛的异步是经过回调函数。

好比,若是你调用fetchData(callback)函数去拉取异步数据而且结束时候调用callback(data)。你要测试的数据是否等于peanut buter

默认状况下,Jest走完测试代码就完成测试。这意味着测试不能定期进行。

// Don't do this!
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});复制代码

问题在于测试工做将在fetchData结束的时候,也就是在回调函数以前结束。

为了解决这个问题,这是另外一种形式。使用参数done来代替无参函数。Jest将会延迟测试直到done回调函数执行完毕。

test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});复制代码

若是done一直没有调用,测试将会失败。

Promises

若是你使用promise,有一种简单的方法处理异步测试。你的测试代码中Jest返回一个Promise,而且等待Promiseresolve。若是Promiserejected,测试自动失败。

好比,仍是那个fetchData,此次使用了回调,返回一个promise假定reslove一个字符串peanut butter。测试代码以下:

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});复制代码

确保返回一个Promise-若是你省略了return,你的测试代码将会在fetchData以前结束。

你也可使用resolves关键字在你的expect代码后,而后Jest将会把等待状态转换成resolve。若是promiserejected,测试自动失败。

test('the data is peanut butter', () => {
  return expect(fetchData()).resolves.toBe('peanut butter');
});复制代码

Async/Await

若是你使用async/await,你能够完美嵌入测试。写一个async测试,仅使用async关键字在你的matchers函数前面就能经过测试。好比,仍是fetchData这个测试方案能够写成

test('the data is peanut butter', async () => {
  await expect(fetchData()).resolves.toBe('peanut butter');
});复制代码

在这种状况下,async/await仅仅是个有效的promises样例的逻辑语法糖。

这些表单特别优秀,你能够混合使用这些在你的代码库或者单个文件中,它仅仅使你的测试变得更加简单。

安装与卸载

写测试的过程当中,在你运行测试以前,你须要作一些初始化工做,去作一些须要测试的事情以前,而且你须要作一些结束工做,去作一些测试结束的事情。Jest提供了helper函数去处理这些工做。

多测试重复初始化

若是你有不少测试有重复的工做,你能够是使用beforeEachafterEach

好比你有不少测试运行以前须要调用initializeCityDatabase(),并且测试结束 后须要调用clearCityDatabase()。你能够这么作:

beforeEach(() => {
  initializeCityDatabase();
});

afterEach(() => {
  clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});复制代码

一样的,若是你的initializeCityDatabase函数返回一个promise,你可使用return返回这个函数。

beforeEach(() => {
  return initializeCityDatabase();
});复制代码

一次性设置

若是你有不少测试有共同的重复的工做,而且重复的工做只在测试开始与测试结束的地方运行一次,你能够是使用beforeAllbeforeAll

好比你有一个测试开始以前要调用initializeCityDatabase(),并且测试结束 后须要调用clearCityDatabase()。你能够这么作:

beforeAll(() => {
  return initializeCityDatabase();
});

afterAll(() => {
  return clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});复制代码

范围

默认状况下,beforeafter会对文件的每一个测试生效。若是你只想对某些测试生效,你可使用describe块。 beforeafter仅仅会在声明块中运行。

好比,咱们不只须要城市初始化,还须要食物初始化,咱们能够对不一样的测试作不一样的初始化。

// Applies to all tests in this file
beforeEach(() => {
  return initializeCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

describe('matching cities to foods', () => {
  // Applies only to tests in this describe block
  beforeEach(() => {
    return initializeFoodDatabase();
  });

  test('Vienna <3 sausage',="" ()=""> {
    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  });

  test('San Juan <3 plantains',="" ()=""> {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});
  
  
  

 
  
  
  

 复制代码

建议

若是你仅仅想测试一个测试用例,或者跨过某个测试用例,你可使用fitxit

fit('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

xit('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

test('this test will not run', () => {
  expect('A').toBe('A');
});复制代码
相关文章
相关标签/搜索