前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jest测试语法系列之Expect

Jest测试语法系列之Expect

作者头像
xiangzhihong
发布2022-11-30 14:56:03
3.6K0
发布2022-11-30 14:56:03
举报
文章被收录于专栏:向治洪

Methods

Expect主要用于实现验证操作,Jest的Expect提供了如下的验证方法:

  • expect(value)
  • expect.extend(matchers)
  • expect.anything()
  • expect.any(constructor)
  • expect.arrayContaining(array)
  • expect.assertions(number)
  • expect.hasAssertions()
  • expect.not.arrayContaining(array)
  • expect.not.objectContaining(object)
  • expect.not.stringContaining(string)
  • expect.not.stringMatching(string | regexp)
  • expect.objectContaining(object)
  • expect.stringContaining(string)
  • expect.stringMatching(string | regexp)
  • expect.addSnapshotSerializer(serializer)
  • .not
  • .resolves
  • .rejects
  • .toBe(value)
  • .toHaveBeenCalled()
  • .toHaveBeenCalledTimes(number)
  • .toHaveBeenCalledWith(arg1, arg2, …)
  • .toHaveBeenLastCalledWith(arg1, arg2, …)
  • .toHaveBeenNthCalledWith(nthCall, arg1, arg2, …)
  • .toHaveReturned()
  • .toHaveReturnedTimes(number)
  • .toHaveReturnedWith(value)
  • .toHaveLastReturnedWith(value)
  • .toHaveNthReturnedWith(nthCall, value)
  • .toBeCloseTo(number, numDigits)
  • .toBeDefined()
  • .toBeFalsy()
  • .toBeGreaterThan(number)
  • .toBeGreaterThanOrEqual(number)
  • .toBeLessThan(number)
  • .toBeLessThanOrEqual(number)
  • .toBeInstanceOf(Class)
  • .toBeNull()
  • .toBeTruthy()
  • .toBeUndefined()
  • .toContain(item)
  • .toContainEqual(item)
  • .toEqual(value)
  • .toHaveLength(number)
  • .toMatch(regexpOrString)
  • .toMatchObject(object)
  • .toHaveProperty(keyPath, value)
  • .toMatchSnapshot(propertyMatchers, snapshotName)
  • .toMatchInlineSnapshot(propertyMatchers, inlineSnapshot)
  • .toStrictEqual(value)
  • .toThrow(error)
  • .toThrowErrorMatchingSnapshot()
  • .toThrowErrorMatchingInlineSnapshot()

Reference

expect(value)

每当您希望测试某个值时,就可以使用expect函数,你可能很少会调用expect本身,相反,你将使用expect和“matcher”函数来断言关于值的某些内容。为了更方便理解,这里假设您有一个方法bestLaCroixFlavor(),,它的expect期望返回结果为:

代码语言:javascript
复制
test('the best flavor is grapefruit', () => {
  expect(bestLaCroixFlavor()).toBe('grapefruit');
});

在上面的例子中,toBe是matcher函数,为了帮助你测试不同的内容,Jest提供了很多不同的matcher函数。expect的参数应该是代码生成的值,而匹配程序的任何参数都应该是正确的值。

expect.extend(matchers)

你可以使用expect.extend将自己的matcher添加到Jest中。例如,假设你正在测试一个 theory library,并且你经常断言数字可以被其他数整除,你可以把它抽象成toBeDivisibleBy matcher。

代码语言:javascript
复制
expect.extend({
  toBeDivisibleBy(received, argument) {
    const pass = received % argument == 0;
    if (pass) {
      return {
        message: () =>
          `expected ${received} not to be divisible by ${argument}`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be divisible by ${argument}`,
        pass: false,
      };
    }
  },
});
 
test('even and odd numbers', () => {
  expect(100).toBeDivisibleBy(2);
  expect(101).not.toBeDivisibleBy(2);
  expect({apples: 6, bananas: 3}).toEqual({
    apples: expect.toBeDivisibleBy(2),
    bananas: expect.not.toBeDivisibleBy(2),
  });
});

expect.extends还支持异步匹配器,异步匹配器返回一个promise,因此你需要等待返回的值。让我们使用一个示例matcher来说明它们的用法。我们要实现一个非常相似的matcher,而不是toBeDivisibleBy,唯一的区别是可分割的数字将从外部源中提取。

代码语言:javascript
复制
expect.extend({
  async toBeDivisibleByExternalValue(received) {
    const externalValue = await getExternalValueFromRemoteSource();
    const pass = received % externalValue == 0;
    if (pass) {
      return {
        message: () =>
          `expected ${received} not to be divisible by ${externalValue}`,
        pass: true,
      };
    } else {
      return {
        message: () =>
          `expected ${received} to be divisible by ${externalValue}`,
        pass: false,
      };
    }
  },
});
 
test('is divisible by external value', async () => {
  await expect(100).toBeDivisibleByExternalValue();
  await expect(101).not.toBeDivisibleByExternalValue();
});

匹配器应该返回带有两个键的对象(或对象的promise)。pass指示是否存在匹配,message提供了一个没有参数的函数,在失败时返回错误消息。因此当pass为false时,当expect(x). yourmatcher()失败时,消息应该返回错误消息。当pass为true时,消息应该返回expect(x).no . yourmatcher()失败时的错误消息。

this.equals(a, b)

如果两个对象具有相同的值(递归地),则返回true。this.utils有很多有用的工具,utils主要由来自jest-matcher-utils的导出组成。最有用的是matcherHint、printExpected和printReceived,它们可以很好地格式化错误消息。

代码语言:javascript
复制
const diff = require('jest-diff');
expect.extend({
  toBe(received, expected) {
    const pass = Object.is(received, expected);
 
    const message = pass
      ? () =>
          this.utils.matcherHint('.not.toBe') +
          '\n\n' +
          `Expected value to not be (using Object.is):\n` +
          `  ${this.utils.printExpected(expected)}\n` +
          `Received:\n` +
          `  ${this.utils.printReceived(received)}`
      : () => {
          const diffString = diff(expected, received, {
            expand: this.expand,
          });
          return (
            this.utils.matcherHint('.toBe') +
            '\n\n' +
            `Expected value to be (using Object.is):\n` +
            `  ${this.utils.printExpected(expected)}\n` +
            `Received:\n` +
            `  ${this.utils.printReceived(received)}` +
            (diffString ? `\n\nDifference:\n\n${diffString}` : '')
          );
        };
 
    return {actual: received, message, pass};
  },
}); 

执行上面的代码,会报如下的错误信息:

代码语言:javascript
复制
expect(received).toBe(expected)
 
   Expected value to be (using Object.is):
     "banana"
   Received:
     "apple"

当断言失败时,错误消息应该向用户提供必要的尽可能多的信号,以便用户能够快速地解决问题。因此,你应该编写一个精确的失败消息,以确保自定义断言的用户具有良好的开发经验。

expect.anything()

它匹配除null或undefined之外的任何内容。你可以在内部使用toEqual或toBeCalledWith而不是文字值。例如如果你想检查一个模拟函数是否被调用,它的参数是非空的:

代码语言:javascript
复制
test('map calls its argument with a non-null argument', () => {
  const mock = jest.fn();
  [1].map(x => mock(x));
  expect(mock).toBeCalledWith(expect.anything());
});

expect.any(constructor)

匹配给定构造函数所创建的任何内容。你可以在内部使用toEqual或toBeCalledWith而不是文字值。例如,如果你想检查一个模拟函数是否被调用时带有一个数字。

代码语言:javascript
复制
function randocall(fn) {
  return fn(Math.floor(Math.random() * 6 + 1));
}
 
test('randocall calls its callback with a number', () => {
  const mock = jest.fn();
  randocall(mock);
  expect(mock).toBeCalledWith(expect.any(Number));
});

expect.arrayContaining(array)

匹配一个接收到的数组,该数组包含预期数组中的所有元素,也就是说预期数组是接收数组的子集,因此它匹配一个接收到的数组,该数组包含不属于预期数组的元素。

代码语言:javascript
复制
describe('arrayContaining', () => {
  const expected = ['Alice', 'Bob'];
  it('matches even if received contains additional elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  });
  it('does not match if received does not contain expected elements', () => {
    expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));
  });
});
代码语言:javascript
复制
describe('Beware of a misunderstanding! A sequence of dice rolls', () => {
  const expected = [1, 2, 3, 4, 5, 6];
  it('matches even with an unexpected number 7', () => {
    expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual(
      expect.arrayContaining(expected)
    );
  });
  it('does not match without an expected number 2', () => {
    expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual(
      expect.arrayContaining(expected),
    );
  });
});

expect.assertions(number)

验证在测试期间调用了一定数量的断言,在测试异步代码时这通常很有用,以便确保回调中的断言确实被调用。 假设我们有一个函数doAsync,它接收两个回调callback1和callback2,它将异步地以一个未知的顺序调用它们。

代码语言:javascript
复制
test('doAsync calls both callbacks', () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }
 
  doAsync(callback1, callback2);
});

expect.hasAssertions()

验证在测试期间至少调用了一个断言。在测试异步代码时,这通常很有用以便确保回调中的断言确实被调用。

假设我们有一些处理状态的函数,prepareState调用一个状态对象的回调,validateState运行在那个状态对象上,waitOnState返回一个承诺,直到所有prepareState回调完成。

代码语言:javascript
复制
test('prepareState prepares a valid state', () => {
  expect.hasAssertions();
  prepareState(state => {
    expect(validateState(state)).toBeTruthy();
  });
  return waitOnState();
});

expect.not.arrayContaining(array)

匹配所接收的数组,该数组不包含预期数组中的元素。也就是说,预期的数组不是接收数组的子集,它与 expect.arrayContaining 相反。

代码语言:javascript
复制
describe('not.arrayContaining', () => {
  const expected = ['Samantha'];
 
  it('matches if the actual array does not contain the expected elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(
      expect.not.arrayContaining(expected),
    );
  });
});

expect.not.objectContaining(object)

匹配任何未递归地匹配预期属性的接收对象。也就是说预期对象不是接收对象的子集。因此,它匹配所接收的对象,该对象包含不属于预期对象的属性。它与expect. objectcontains相反。

代码语言:javascript
复制
describe('not.objectContaining', () => {
  const expected = {foo: 'bar'};
 
  it('matches if the actual object does not contain expected key: value pairs', () => {
    expect({bar: 'baz'}).toEqual(expect.not.objectContaining(expected));
  });
});

expect.not.stringContaining(string)

匹配不包含确切期望字符串的接收字符串,它与expect.stringContaining.相反。

代码语言:javascript
复制
describe('not.stringContaining', () => {
  const expected = 'Hello world!';
 
  it('matches if the actual string does not contain the expected substring', () => {
    expect('How are you?').toEqual(expect.not.stringContaining(expected));
  });
});

expect.not.stringMatching(string | regexp)

匹配不匹配预期regexp的接收字符串,它与expect.stringMatching.相反。

代码语言:javascript
复制
describe('not.stringMatching', () => {
  const expected = /Hello world!/;
 
  it('matches if the actual string does not match the expected regex', () => {
    expect('How are you?').toEqual(expect.not.stringMatching(expected));
  });
});

expect.objectContaining(object)

匹配递归地匹配预期属性的任何接收对象。也就是说,预期对象是接收对象的子集。因此,它匹配所接收的对象,该对象包含不属于预期对象的属性。

与期望对象中的文字属性值不同,您可以使用matchers、expect.anything()等等。假设我们希望使用事件对象调用onPress函数,我们需要验证的是事件是否有event.x属性和y属性。

代码语言:javascript
复制
test('onPress gets called with the right thing', () => {
  const onPress = jest.fn();
  simulatePresses(onPress);
  expect(onPress).toBeCalledWith(
    expect.objectContaining({
      x: expect.any(Number),
      y: expect.any(Number),
    }),
  );
});

expect.stringMatching(string | regexp)

匹配与预期regexp匹配的接收字符串,你可以用它代替文字的值:

  1. 在toEqual或toBeCalledWith
  2. 匹配arraycontains中的元素
  3. 匹配objectContaining 或者toMatchObject的属性
代码语言:javascript
复制
describe('stringMatching in arrayContaining', () => {
  const expected = [
    expect.stringMatching(/^Alic/),
    expect.stringMatching(/^[BR]ob/),
  ];
  it('matches even if received contains additional elements', () => {
    expect(['Alicia', 'Roberto', 'Evelina']).toEqual(
      expect.arrayContaining(expected),
    );
  });
  it('does not match if received does not contain expected elements', () => {
    expect(['Roberto', 'Evelina']).not.toEqual(
      expect.arrayContaining(expected),
    );
  });
});

.toBe(value)

toBe只是检查一个值是否符合您的期望。如果它使用的是对象,则是要检查完全相等。

代码语言:javascript
复制
const can = {
  name: 'pamplemousse',
  ounces: 12,
};
 
describe('the can', () => {
  test('has 12 ounces', () => {
    expect(can.ounces).toBe(12);
  });
 
  test('has a sophisticated name', () => {
    expect(can.name).toBe('pamplemousse');
  });
});

.toEqual(value)

如果要检查两个对象是否具有相同的值,请使用. toequal。此matcher递归地检查所有字段的相等性,而不是检查对象标识——这也称为“深度相等”。例如,toEqual和toBe在这个测试套件中表现不同,所以所有的测试都通过。

代码语言:javascript
复制
const can1 = {
  flavor: 'grapefruit',
  ounces: 12,
};
const can2 = {
  flavor: 'grapefruit',
  ounces: 12,
};
 
describe('the La Croix cans on my desk', () => {
  test('have all the same properties', () => {
    expect(can1).toEqual(can2);
  });
  test('are not the exact same can', () => {
    expect(can1).not.toBe(can2);
  });
});

.toMatchObject(object)

使用. tomatchobject检查一个JavaScript对象是否匹配一个对象的属性子集。它将把接收到的对象与预期对象中没有的属性匹配起来。

您还可以传递一个对象数组,在这种情况下,只有当接收到的数组中的每个对象(在上面描述的番茄对象意义中)与预期数组中的相应对象相匹配时,该方法才会返回true。如果想要检查两个数组在它们的元素数量上是否匹配,而不是arrayinclude,这是非常有用的,因为它允许在接收的数组中添加额外的元素。

代码语言:javascript
复制
const houseForSale = {
  bath: true,
  bedrooms: 4,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    area: 20,
    wallColor: 'white',
  },
};
const desiredHouse = {
  bath: true,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    wallColor: expect.stringMatching(/white|yellow/),
  },
};
 
test('the house has my desired features', () => {
  expect(houseForSale).toMatchObject(desiredHouse);
});
代码语言:javascript
复制
describe('toMatchObject applied to arrays arrays', () => {
  test('the number of elements must match exactly', () => {
    expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]);
  });
 
  // .arrayContaining "matches a received array which contains elements that
  // are *not* in the expected array"
  test('.toMatchObject does not allow extra elements', () => {
    expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}]);
  });
 
  test('.toMatchObject is called for each elements, so extra object properties are okay', () => {
    expect([{foo: 'bar'}, {baz: 1, extra: 'quux'}]).toMatchObject([
      {foo: 'bar'},
      {baz: 1},
    ]);
  });
});

.toHaveProperty(keyPath ,value)

使用. tohaveproperty检查在提供的引用keyPath中是否存在对象的属性。要检查对象中深度嵌套的属性,可以使用点表示法或包含深度引用的keyPath的数组。

可选地,你可以提供一个值来检查它是否等于目标对象的keyPath中的值。此matcher使用“深度相等”(如toEqual()))并递归地检查所有字段的相等性。

下面的示例包含一个带有嵌套属性的houseForSale对象。我们使用tohave属性来检查对象中各种属性的存在性和值。

代码语言:javascript
复制
const houseForSale = {
  bath: true,
  bedrooms: 4,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    area: 20,
    wallColor: 'white',
    'nice.oven': true,
  },
};
 
test('this house has my desired features', () => {
  // Simple Referencing
  expect(houseForSale).toHaveProperty('bath');
  expect(houseForSale).toHaveProperty('bedrooms', 4);
 
  expect(houseForSale).not.toHaveProperty('pool');
 
  // Deep referencing using dot notation
  expect(houseForSale).toHaveProperty('kitchen.area', 20);
  expect(houseForSale).toHaveProperty('kitchen.amenities', [
    'oven',
    'stove',
    'washer',
  ]);
 
  expect(houseForSale).not.toHaveProperty('kitchen.open');
 
  // Deep referencing using an array containing the keyPath
  expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20);
  expect(houseForSale).toHaveProperty(
    ['kitchen', 'amenities'],
    ['oven', 'stove', 'washer'],
  );
  expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');
  expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']);
  expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);
});

其他: 前端单元测试之Jest React测试框架之enzyme Jest测试语法系列之Globals Jest测试语法系列之Matchers

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Methods
  • Reference
    • expect(value)
      • expect.extend(matchers)
        • this.equals(a, b)
          • expect.anything()
            • expect.any(constructor)
              • expect.arrayContaining(array)
                • expect.assertions(number)
                  • expect.hasAssertions()
                    • expect.not.arrayContaining(array)
                      • expect.not.objectContaining(object)
                        • expect.not.stringContaining(string)
                          • expect.not.stringMatching(string | regexp)
                            • expect.objectContaining(object)
                              • expect.stringMatching(string | regexp)
                                • .toBe(value)
                                  • .toEqual(value)
                                    • .toMatchObject(object)
                                      • .toHaveProperty(keyPath ,value)
                                      领券
                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档