Дразнящие занятия с Jest - PullRequest
       25

Дразнящие занятия с Jest

1 голос
/ 25 апреля 2019

Учитывая, что у меня есть класс, который вызывает функцию doStuff примерно так:


const myService = require(`./myService`),
    service = new myService();

exports.doStuff = async (callback) => {
    try {
        const data = await service.doOtherStuff(); //I want to mock this

        return callback(null, data);
    } catch (err) {
        callback(new Error(` > feed failed for ${key}, error: ${err}`));
    }
};

мои тесты работают так:

const myClass = require(`../index`);
jest.mock(`./../myService`, () => {
    return function() {
        return {
            doOtherStuff: () => {
                return 1;
            }
        };
    };
});

describe(`service-tests - index`, () => {
        test(`doStuff and test otherStuff`, async () => {
            const result = await myClass.doStuff((err, data) => {
                return data;
            });

            expect(result).toBe(1);
        });
});

И мой сервис:

class myService{
    constructor() {
        //Do constructor stuff
    }

    async doOtherStuff() {
        //Do other stuff
    }

Это работает, но теперь у меня есть мой макет этого файла, а не тестирование. Что мне нужно, так это чтобы мой тест был изменяемым по тестам, но не могу понять, как это работает вместе с require.

Я пытался просто сделать jest.mock('./../myService') и иметь mockImplementation на beforeAll, но это будет удерживать мою функцию в замешательстве, как кажется, при автоматической имитации, возвращая undefined

Кто-нибудь когда-либо делал это раньше?

Ответы [ 2 ]

2 голосов
/ 25 апреля 2019

Если вы хотите смоделировать метод в классе, который выглядит так, как вы делаете, я бы предложил вам использовать jest.spyOn .Это просто, и вы можете смоделировать возвращаемое значение таким, какое хотите в каждом тесте.

const myClass = require('../index');
const myService = require('../myService');

describe('service-tests - index', () => {

  let doOtherStuffMock;
  beforeAll(() => {
    doOtherStuffMock = jest.spyOn(myService.prototype, 'doOtherStuff');
  });

  it('mocks doOtherStuff one way', async () => {
    doOtherStuffMock.mockResolvedValue('I am a mocked value');
    const result = await myClass.doStuff((err, data) => data);
    expect(result).toBe("I am a mocked value");
  });

  it('mocks doOtherStuff another way', async () => {
    doOtherStuffMock.mockResolvedValue('I am DIFFERENT mocked value');
    const result = await myClass.doStuff((err, data) => data);
    expect(result).toBe('I am DIFFERENT mocked value');
  });
});
1 голос
/ 25 апреля 2019

Обновление

Я оставлю этот ответ здесь, так как оба эти подхода работают, и они могут быть полезны ...

... но для этого конкретного случая @Daniel прав, дразнить метод прототипа проще всего


Простой способ справиться с этим - это смоделировать myService.js как синглтон ...

... тогда вы можете получить фиктивную функцию для doOtherStuff и изменить ее для каждого теста:

const myClass = require(`../index`);

jest.mock(`../myService`, () => {
  const doOtherStuff = jest.fn();  // <= create a mock function for doOtherStuff
  const result = { doOtherStuff };
  return function() { return result; };  // <= always return the same object
});
const doOtherStuff = require('./myService')().doOtherStuff;  // <= get doOtherStuff

describe(`service-tests - index`, () => {

  test(`doStuff and test otherStuff`, async () => {
    doOtherStuff.mockReturnValue(1);  // <= mock it to return something
    const result = await myClass.doStuff((err, data) => data);
    expect(result).toBe(1);  // Success!
  });

  test(`doStuff and test otherStuff`, async () => {
    doOtherStuff.mockReturnValue('something else');  // <= mock it to return something else
    const result = await myClass.doStuff((err, data) => data);
    expect(result).toBe('something else');  // Success!
  });
});

Он также работает для автоматического макета myService.js и использования mockImplementation ...

... но поскольку index.js создает myService экземпляр , как только он запускается , вы должны убедиться, что макет на месте до , вам требуется index.js :

jest.mock(`../myService`);  // <= auto-mock
const myService = require('../myService');
const doOtherStuff = jest.fn();
myService.mockImplementation(function() { return { doOtherStuff }; });

const myClass = require(`../index`);  // <= now require index

describe(`service-tests - index`, () => {

  test(`doStuff and test otherStuff`, async () => {
    doOtherStuff.mockReturnValue(1);  // <= mock it to return something
    const result = await myClass.doStuff((err, data) => data);
    expect(result).toBe(1);  // Success!
  });

  test(`doStuff and test otherStuff`, async () => {
    doOtherStuff.mockReturnValue('something else');  // <= mock it to return something else
    const result = await myClass.doStuff((err, data) => data);
    expect(result).toBe('something else');  // Success!
  });
});
...