My-Note-Blog icon indicating copy to clipboard operation
My-Note-Blog copied to clipboard

jest基础

Open huangchucai opened this issue 6 years ago • 0 comments

jest学习总结

最近要给项目添加单元测试,所以总结一下jest单元测试的语法点和单元测试的用意。

为什么要写单元测试

  1. 保持代码的可持续迭代
  2. 减少bug
  3. 减少调试时间
  4. 放心的进行重构

基本语法

相等判定

  1. toBe() => 实现原理是Object.is()
  2. toEqual() => 针对object
  3. not.toBe(). => 不相等
 test('object assignment', () => {
		const data = {one: 1}
		data['two'] =  2
		expect(data).toEqual({one: 1, two: 2})
 })
 test('two plus two is four', () => {
		expect(2 + 2).toBe(4)
 })

常见的false判定

  1. toBeNull() 只匹配null
  2. toBeUndefined 只匹配undefined
  3. toBeDefined 只要不是undefined
  4. toBeTruthy 只要是true可以
  5. toBeFalsy 只要是false就可以
test('null',() => {
    const n = null;
    expect(n).toBeNull();
    expect(n).toBeDefined();
    expect(n).not.toBeUndefined();
    expect(n).not.toBeTruthy();
    // expect(n).toBeUndefined();
    expect(n).toBeFalsy();
})

常见的数字判定

  1. toBeGreaterThan() 大于期待值
  2. toBeGreaterThanOrEqual() 大于或者等于期待值
  3. ToBeLessThan() 小于期待值
  4. toBeLessThanOrEqual() 小于或者等于期待值
  5. toBeCloseTo() 接近于这个值 0.1+0.2
test('Number', () => {
    const value = 2 + 2;
    const float = 0.1 + 0.2;
    expect(value).toBeGreaterThan(3);
    expect(value).toBeGreaterThanOrEqual(4);
    expect(value).toBeLessThan(4.5);
    expect(value).toBe(4);
    expect(value).toEqual(4);
    expect(float).toBeCloseTo(0.3);

})

字符串测试

  1. toMatch() 使用正则进行匹配
  2. not.toMatch() 不匹配
test('String', () => {
    expect('team').not.toMatch(/I/);
    expect('Chritshop').toMatch(/shop/);
})

数组

  1. toContain() 判定包含期待值
test('Array',() => {
    const arr = [1,2,3,4,5];
    expect(arr).toContain(3);
})

函数抛出错误

  1. toThrow() 抛出对应的错误
function compileCode() {
    throw new Error('you are using the wrong JDK');
}
test('function', () => {
    expect(compileCode).toThrow();
    expect(compileCode).toThrow(Error);
    expect(compileCode).toThrow('you are using the wrong JDK');
})

异步函数

callback

  1. callback验证
  • 如果不添加done的回调函数,当我们的test函数执行完成后,异步还没有执行完,无法判定是否有错误。如果是同步的代码就不要添加done的回调函数
  • 根据done()是否被调用来判定,是否返回的数据正常
// 同步执行,不需要添加done(可以简化)
function fetchDataSync(callback) {
    callback('peanut butter');
}
test('sync callback', () => {
    function callback(data) {
        expect(data).toBe('peanut butter');
    }
    fetchDataSync(callback);
})

// 异步执行
function fetchData(callback) {
    // 请求接口,1秒钟后返回数据
    setTimeout(() => {
        callback('peanut butter');
    }, 1000)
}
// 如果不添加done的参数的时候,当callback被执行的时候,我们的test函数已经执行完成,不能判定是否有出错。
// jest根据是否done函数被执行来判定是否通过测试
test('the data is peanut butter', (done) => {
    function callback(data) {
        expect(data).toBe('peanut butter');
        done()
    }
    fetchData(callback);
})

promises

  1. 记住一定要return promise的状态,不然等到我们test执行完成,异步的返回结果不知道是不是正确,得到不到测试
  2. 判定promise的reject方法执行,需要使用catch()方法
  3. 可以使用rejects和resolves属性来分别对promise的进行测试,它们会等待promise执行完成后再执行(记住返回状态), 不需要使用expect.assertions(1)
function promiseFetchData() {
    return new Promise((resolve, reject) => {
        resolve('promise data')
    })
}
test('async promise resolve', () => {
    // expect.assertions(1);
    return expect(promiseFetchData()).resolves.toBe('promise data');
})
test('the fetch fails with an error', () => {
  return expect(fetchData()).rejects.toMatch('error');
});

assertions(1): 这里指的是断言必须只有一次,如果没有的话,就会报错,多余一次也会报错

Async/Await

  1. 使用常规的async和await,来判定数据是否正确
  2. 使用resolves和rejects属性来判定返回的promise
test('await syntax', async () => {
    const data = await promiseFetchData()
    expect.assertions(1);
    expect(data).toBe('promise data')
})
test('await syntax fail', async () => {
    expect.assertions(1);
    try {
       await errorPromise();
    } catch (e) {
        expect(e).toMatch('error')
    }
})

安装和移除

beforeEach和afterEach

  1. 每执行一次单元测试test,都会触发beforeEach和afterEach的方法
  2. 可以用于异步请求接口,来初始化数据
function initializeCityDatabase(data) {
    return new Promise((resolve) => {
        resolve(data)
        console.log(data)
    })
}
beforeEach(() => {
    console.log('beforeEach');
    initializeCityDatabase('beforeEach-promise');
})
afterEach(() => {
    console.log('afterEach');
})
test('test1', () => {
	  console.log('test)
    expect('hcc').toBe('hcc')
})
test('test2', () => {
    expect('hcc1').toBe('hcc1')
})
// 输出
   beforeEach
   beforeEach-promise
	 test
   afterEach
   beforeEach
   beforeEach-promise
   afterEach

beforeAll和afterAll

  1. 用于一次性的处理数据,一般用于全局请求一次接口的数据

describe作用域

  1. 一般before和after块,都会作用于整个文件,但是如果添加describe块来给测试用例分组,就只会作用于对应的describe块
  2. 顶层的before块会在describe块之前执行
function initializeCityDatabase(data) {
    return new Promise((resolve) => {
        resolve(data)
        console.log(data)
    })
}
beforeEach(() => {
    console.log('beforeEach');
    initializeCityDatabase('beforeEach-promise');
})
beforeAll(() => {
    initializeCityDatabase('beforeAll-promise')
})

afterEach(() => {
    console.log('afterEach');
})
afterAll(() => {
    console.log('afterAll');
})

test('test1', () => {
    console.log('test');
    expect('hcc').toBe('hcc')
})
describe('代码块', () => {
    beforeEach(() => {
        console.log('describe beforeEach');
    })
    afterEach(() => {
        console.log('describe afterEach');
    })
    test('', () => {
        console.log('describe test')
    })
})


beforeAll-promise
beforeEach
beforeEach-promise
test
afterEach
beforeEach
beforeEach-promise
describe beforeEach
describe test
describe afterEach
afterEach
¡afterAll

huangchucai avatar Aug 21 '19 03:08 huangchucai