0

I am trying to mock the return value of a method of a class which is instantiated inside of the class I am testing, without it persisting the mocked value across the rest of the tests.

Here is a very basic demo I've put together:

Mystery.ts

export class Mystery {
    private max = 10;

    public getNumber(): number {
        return Math.random() * this.max;
    }
}

TestedClass.ts

import { Mystery } from './Mystery';

export class TestedClass {
    public someMethod() {
        const numberGenerator = new Mystery();

        return numberGenerator.getNumber();
    }
}

TestedClass.test.ts

import { Mystery } from './Mystery';
import { TestedClass } from './TestedClass';

jest.mock('./Mystery');

describe('TestedClass', () => {
    beforeEach(jest.clearAllMocks);

    it('should return the number 1000', () => {
        // I want to have Mystery.getNumber() return 1000 for this test only.

        Mystery.prototype.getNumber = jest.fn().mockReturnValue(1000);
        // jest.spyOn(Mystery.prototype, 'getNumber').mockReturnValue(1000);
        // Mystery.prototype.getNumber = jest.fn().mockReturnValueOnce(1000);

        const provider = new TestedClass();
        const result = provider.someMethod();

        expect(result).toEqual(1000);
    });

    it('should return undefined', () => {
        const provider = new TestedClass();
        const result = provider.someMethod();

        // Expects: undefined, Received: 1000
        expect(result).toEqual(undefined);
    });
});

As you can see from the test, I am seeing 1000 appear in the second test which I would like to avoid. In the real scenario all of the tests will likely need to mock the return value of Mystery.getNumber() (in different ways) but I want to ensure that one test is not affecting another test as it could be now.

This current behaviour does make sense as I am changing the Mystery.prototype but I'm not sure how to mock the value for individual test in any other way. I am also aware of using composition, which would help tremendously here, but I would like to avoid this for the sake of this question.

1
  • Did you read jestjs.io/docs/es6-class-mocks? That covers mocking out the class. There's also dependency inversion, passing in an instance of Mystery rather than getting TestedClass to new one up; that would substantially reduce coupling and make it trivial to test.
    – jonrsharpe
    Commented Oct 13, 2021 at 16:40

1 Answer 1

1

If you're trying to mock the getNumber method for a single test case only and not for all test cases, the jest.fn().mockReturnValueOnce method should do the trick.

So instead of

Mystery.prototype.getNumber = jest.fn().mockReturnValue(1000);

use

Mystery.prototype.getNumber = jest.fn().mockReturnValueOnce(1000);
2
  • All test cases will need to mock the return value in different ways. I just don't want one test to affect another test. I have updated the question to hopefully clarify Commented Oct 13, 2021 at 11:28
  • @RyanPeterson Thanks for clarifying. I have updated the answer to add more clarity. Hope it helps Commented Oct 18, 2021 at 10:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.