Supongamos que tengo la siguiente clase:
export default class Person { constructor(first, last) { this.first = first; this.last = last; } sayMyName() { console.log(this.first + " " + this.last); } bla() { return "bla"; } }Supongamos que quiero crear una clase simulada donde el método 'sayMyName' se simulará y el método 'bla' permanecerá como está.
La prueba que escribí es:
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 primera declaración 'esperar' pasa, lo que significa que 'sayMyName' se burló con éxito. Pero, el segundo 'esperar' falla con el error:
TypeError: person.bla no es una función
Entiendo que la clase simulada borró todos los métodos. Quiero saber cómo simular una clase de modo que solo se simularán métodos específicos.
Usar jest.spyOn() es la forma adecuada de Jest de burlarse de un solo método y dejar el resto en paz. En realidad, hay dos enfoques ligeramente diferentes para esto.
1. Modificar el método solo en un solo objeto
import Person from "./Person"; test('Modify only instance', () => { let person = new Person('Lorem', 'Ipsum'); let spy = jest.spyOn(person, 'sayMyName').mockImplementation(() => 'Hello'); expect(person.sayMyName()).toBe("Hello"); expect(person.bla()).toBe("bla"); // unnecessary in this case, putting it here just to illustrate how to "unmock" a method spy.mockRestore(); });2. Modifique la clase en sí, para que todas las instancias se vean afectadas.
import Person from "./Person"; beforeAll(() => { jest.spyOn(Person.prototype, 'sayMyName').mockImplementation(() => 'Hello'); }); afterAll(() => { jest.restoreAllMocks(); }); test('Modify class', () => { let person = new Person('Lorem', 'Ipsum'); expect(person.sayMyName()).toBe("Hello"); expect(person.bla()).toBe("bla"); });Y en aras de la exhaustividad, así es como te burlarías de un método estático:
jest.spyOn(Person, 'myStaticMethod').mockImplementation(() => 'blah'); Veo que varias personas no están de acuerdo con el siguiente enfoque, y eso es genial. Sin embargo, tengo un ligero desacuerdo con el enfoque de @blade, ya que en realidad no prueba la clase porque está usando mockImplementation . Si la clase cambia, las pruebas siempre pasarán dando falsos positivos. Así que aquí hay un ejemplo con spyOn .
// person.js export default class Person { constructor(first, last) { this.first = first; this.last = last; } sayMyName() { return this.first + " " + this.last; // Adjusted to return a value } bla() { return "bla"; } }y la prueba:
import Person from './' describe('Person class', () => { const person = new Person('Guy', 'Smiley') // Spying on the actual methods of the Person class jest.spyOn(person, 'sayMyName') jest.spyOn(person, 'bla') it('should return out the first and last name', () => { expect(person.sayMyName()).toEqual('Guy Smiley') // deterministic expect(person.sayMyName).toHaveBeenCalledTimes(1) }); it('should return bla when blah is called', () => { expect(person.bla()).toEqual('bla') expect(person.bla).toHaveBeenCalledTimes(1) }) });¡Salud! 🍻
No veo cómo la implementación simulada realmente resuelve algo para usted. Creo que esto tiene un poco más de sentido.
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); }); });He estado haciendo una pregunta similar y creo que encontré una solución. Esto debería funcionar sin importar dónde se use realmente la instancia de la clase Person.
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"); });