Supposons que j'ai le cours suivant:
export default class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
sayMyName() {
console.log(this.first + " " + this.last);
}
bla() {
return "bla";
}
}
Supposons que je veuille créer une classe fausse où la méthode 'sayMyName' sera fausse et la méthode 'bla' restera telle quelle.
Le test que j'ai écrit est:
const Person = require("../Person");
jest.mock('../Person', () => {
return jest.fn().mockImplementation(() => {
return {sayMyName: () => {
return 'Hello'
}};
});
});
let person = new Person();
test('MyTest', () => {
expect(person.sayMyName()).toBe("Hello");
expect(person.bla()).toBe("bla");
})
La première instruction 'expect' passe, ce qui signifie que 'sayMyName' a été moqué avec succès. Mais le second 'expect' échoue avec l'erreur:
TypeError: person.bla n'est pas une fonction
Je comprends que la classe simulée a effacé toutes les méthodes ..__ Je veux savoir comment se moquer d’une classe de telle sorte que seules des méthodes spécifiques soient simulées.
Je ne vois pas comment l'implémentation simulée résoudrait quelque chose pour vous. Je pense que cela fait un peu plus de sens
import Person from "./Person";
describe("Person", () => {
it("should...", () => {
const sayMyName = Person.prototype.sayMyName = jest.fn();
const person = new Person('guy', 'smiley');
const expected = {
first: 'guy',
last: 'smiley'
}
person.sayMyName();
expect(sayMyName).toHaveBeenCalledTimes(1);
expect(person).toEqual(expected);
});
});
Ont posé une question similaire et je pense trouvé une solution. Cela devrait fonctionner peu importe où l'instance de la classe Person est réellement utilisée.
const Person = require("../Person");
jest.mock("../Person", function () {
const { default: mockRealPerson } = jest.requireActual('../Person');
mockRealPerson.prototype.sayMyName = function () {
return "Hello";
}
return mockRealPerson
});
test('MyTest', () => {
const person = new Person();
expect(person.sayMyName()).toBe("Hello");
expect(person.bla()).toBe("bla");
});
plutôt que de se moquer de la classe, vous pouvez l'étendre comme ceci:
class MockedPerson extends Person {
sayMyName () {
return 'Hello'
}
}
// and then
let person = new MockedPerson();
Si vous utilisez TypeScript, vous pouvez effectuer les opérations suivantes:
Person.prototype.sayMyName = jest.fn().mockImplementationOnce(async () =>
await 'my name is dev'
);
Et dans votre test, vous pouvez faire quelque chose comme ça:
const person = new Person();
const res = await person.sayMyName();
expect(res).toEqual('my name is dev');
J'espère que cela aide quelqu'un!
J'ai combiné les réponses @sesamechicken et @Billy Reilly pour créer une fonction util qui simule (une ou plusieurs) méthodes spécifiques d'une classe, sans impacter de manière définitive la classe elle-même.
/**
* @CrazySynthax class, a tiny bit updated to be able to easily test the mock.
*/
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
sayMyName() {
return this.first + " " + this.last + this.yourGodDamnRight();
}
yourGodDamnRight() {
return ", you're god damn right";
}
}
/**
* Return a new class, with some specific methods mocked.
*
* We have to create a new class in order to avoid altering the prototype of the class itself, which would
* most likely impact other tests.
*
* @param Klass: The class to mock
* @param functionNames: A string or a list of functions names to mock.
* @returns {Class} a new class.
*/
export function mockSpecificMethods(Klass, functionNames) {
if (!Array.isArray(functionNames))
functionNames = [functionNames];
class MockedKlass extends Klass {
}
const functionNamesLenght = functionNames.length;
for (let index = 0; index < functionNamesLenght; ++index) {
let name = functionNames[index];
MockedKlass.prototype[name] = jest.fn();
};
return MockedKlass;
}
/**
* Making sure it works
*/
describe('Specific Mocked function', () => {
it('mocking sayMyName', () => {
const walter = new (mockSpecificMethods(Person, 'yourGodDamnRight'))('walter', 'white');
walter.yourGodDamnRight.mockReturnValue(", that's correct"); // yourGodDamnRight is now a classic jest mock;
expect(walter.sayMyName()).toBe("walter white, that's correct");
expect(walter.yourGodDamnRight.mock.calls.length).toBe(1);
// assert that Person is not impacted.
const saul = new Person('saul', 'goodman');
expect(saul.sayMyName()).toBe("saul goodman, you're god damn right");
});
});