简体   繁体   中英

Can I spy on an object rather than an object method?

I know that I can use spy like below to track the number of times a function has been called, when I have a reference to the object on which it is a method.

jest.spyOn(myObj, 'myFunc')

But what do I do when I have a reference to the function that I want to use? jest.spyOn(myFunc) does not work

To clarify, I want to use the real implementation of the function. I just want to be able to see how many times it has been called and with which arguments.

When I try to see those things on an ordinary function I get:

  expect(received).toHaveBeenCalledWith(...expected)
Matcher error: received value must be a mock or spy function

Here is (most of) the actual test:

  it('should set createScrollContextImmediately when result is above the maximum return limit', async () => {
    // Arrange
    ...
    // Act
    await fetch(imageID, { size: maxSizePerScroll }, ids, { createScrollContextImmediately: false });
    // Assert
    expect(fetch).toHaveBeenCalledWith(imageID, { size: maxSizePerScroll }, ids, { createScrollContextImmediately: false });
    expect(fetch).toHaveBeenCalledWith(imageID, { size: maxSizePerScroll }, ids, { createScrollContextImmediately: true });
    expect(fetch).toHaveBeenCalledTimes(2);
  });

Option 1. You can mock the fetch function using jest.mock with the real implementation. And, we can add a spy in the implementation. You can make assertions for that spy.

Eg

fetch.ts :

export async function fetch(name) {
  return 'real implementation';
}

fetch.test.ts :

import { fetch } from './fetch';

const fetchSpy = jest.fn();

jest.mock('./fetch', () => {
  const { fetch } = jest.requireActual('./fetch');
  const fetchWithSpy = jest.fn().mockImplementation((...args) => {
    fetchSpy(...args);
    return fetch(...args);
  });
  return {
    fetch: fetchWithSpy,
  };
});

describe('65266282', () => {
  it('should set createScrollContextImmediately when result is above the maximum return limit', async () => {
    const actual = await fetch('teresa teng');
    expect(actual).toBe('real implementation');
    expect(fetchSpy).toBeCalledWith('teresa teng');
    expect(fetchSpy).toHaveBeenCalledTimes(1);
  });
});

test result:

PASS  examples/65266282/fetch.test.ts
  65266282
    ✓ should set createScrollContextImmediately when result is above the maximum return limit (8 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.216 s

Option 2. You can use Proxy to create a proxy for your fetch function.

The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object.

fetch-v2.test.ts :

import { fetch } from './fetch';

const fetchSpy = jest.fn();
const fetchProxy = new Proxy(fetch, {
  apply: (target, thisArg, argumentsList) => {
    fetchSpy.apply(thisArg, argumentsList);
    return target.apply(thisArg, argumentsList);
  },
});

describe('65266282', () => {
  it('should set createScrollContextImmediately when result is above the maximum return limit', async () => {
    const actual1 = await fetchProxy('teresa teng');
    expect(actual1).toBe('real implementation');
    const actual2 = await fetchProxy('best singer');
    expect(actual2).toBe('real implementation');
    expect(fetchSpy).toBeCalledWith('teresa teng');
    expect(fetchSpy).toBeCalledWith('best singer');
    expect(fetchSpy).toHaveBeenCalledTimes(2);
  });
});

test result:

 PASS  examples/65266282/fetch-v2.test.ts
  65266282
    ✓ should set createScrollContextImmediately when result is above the maximum return limit (3 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.484 s

The two methods are essentially the same. The core idea is to use proxy, interceptor, high order function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM