Reputation: 373
I have class B which is dependent on class A. I want to test a method of class B which is internally calling a method of class A. Now, I want to unit test my method of class B by mocking class A.
My code structure:
class A {
getSomething() {
return "Something";
}
}
class B {
constructor(objectOfClassA: A) {
this._objectOfClassA = objectOfClassA;
}
functionofClassBToTest() {
const returnValueFromClassA = this._objectOfClassA.getSomething();
return returnValueFromClassA;
}
}
What I have tried so far:
import ....
import { mocked } from 'jest-mock';
jest.mock("./A", () => {
return {
A: jest.fn().mockImplementation(() => {
return {
getSomething: getSomethingMock
}
})
};
});
const getSomethingMock = jest.fn().mockImplementation(() => {
return "Mock value";
});
const mockA = mocked(A, true);
test("test functionofClassBToTest", () => {
const classBToTest = new B(mockA);
expect(classBToTest.functionofClassBToTest.toStrictEqual("Mock value");
});
This is the error that I am getting:
TypeError: this._objectOfClassA.getSomething is not a function
Note: I don't want to initialize an object of class A inside my test function. I only want to mock the class.
I also found some previous posts on SO : Post1 and Post2 but nothing worked.
UPDATE: This problem got solved thanks to James's answer below. For mocking classes with private members, I have asked another SO Question. Please do read it.
Upvotes: 16
Views: 23434
Reputation: 770
Given that Typescript is structurally typed, it should be possible to simply construct an object literally that matches the interface of the A class and pass that into class B.
For example:
const mockA: jest.Mocked<A> = {
getSomething: jest.fn()
};
const b = new B(mockA);
expect(mockA.getSomething)
.toHaveBeenCalled();
This should not generate type errors given mockA exactly matches the interface of class A.
To mock the return value of A’s methods, refer to mocking individual functions with Jest.
This proves to be simpler and more succinct than attempting to mock the entire module. Since you’ve used IoC as a pattern, mocking the module is not necessary.
You also have a typo. Class B assigns to an instance variable with only one underscore but then calls the method on an instance variable with two underscores.
Upvotes: 17