Estoy usando un cierre para asegurarme de que algo solo se llame una vez:
var pageDOM = (function() { var mounted = false return { initializePage: function() { if (mounted == false) { pageDOM.addBoxes(); mount = true } pageDOM.otherInitProcedures(); }, otherFunction: function() { } } })(); No estoy seguro de cuál es la forma correcta de pensar en las pruebas unitarias pageDOM.initializePage . Las especificaciones de Jasmine se ejecutan en orden aleatorio, y creo que es importante mantener esto para probar la integridad (es decir, NO me gustaría imponer un orden). Este es mi código de especificación:
describe("pageDOM", function() { describe("initializePage", function() { beforeEach(function() { spyOn(pageDOM, "addBoxes") spyOn(pageDOM, "otherInitProcedures") }) describe("calling initializePage first time", function() { beforeEach(function() { pageDOM.initializePage(); }) it("should call both functions", function() { expect(pageDOM.otherInitProcedures).toHaveBeenCalled() expect(pageDOM.addBoxes).toHaveBeenCalled() }) describe("calling initializePage again", function() { beforeEach(function() { pageDOM.initializePage(); }) it("should only call otherInitProcedures", function() { expect(pageDOM.otherInitProcedures).toHaveBeenCalled() expect(pageDOM.addBoxes).not.toHaveBeenCalled() }) }) }) }) })El problema es que si las especificaciones no se ejecutan en orden, ambas fallarán. ¿Cuál es una manera de probar esto, o debería incluso intentar probar esto?
Asignaría los espías a las variables y restablecería los espías en un gancho afterEach .
Algo como esto (sigue el !! en los comentarios):
describe("pageDOM", function() { describe("initializePage", function() { // !! initialize these variables let addBoxesSpy; let otherInitProceduresSpy; beforeEach(function() { // !! assign the variables addBoxesSpy = spyOn(pageDOM, "addBoxes") otherInitProceduresSpy = spyOn(pageDOM, "otherInitProcedures") }) describe("calling initializePage first time", function() { beforeEach(function() { pageDOM.initializePage(); }) it("should call both functions", function() { expect(pageDOM.otherInitProcedures).toHaveBeenCalled() expect(pageDOM.addBoxes).toHaveBeenCalled() }) describe("calling initializePage again", function() { beforeEach(function() { pageDOM.initializePage(); }) it("should only call otherInitProcedures", function() { expect(pageDOM.otherInitProcedures).toHaveBeenCalled() expect(pageDOM.addBoxes).not.toHaveBeenCalled() }) }) }) // !! Reset the spies in an afterEach afterEach(() => { addBoxesSpy.calls.reset(); otherInitProceduresSpy.calls.reset(); }); }) })Después de restablecer las llamadas a lo que está espiando, el orden ya no debería importar.
Entonces, su método "pageDOM" está lleno de estado, entonces, ¿por qué usar 2 veces describir y configurar la llamada al método "initializePage" cada vez al conectarlo beforeEach? No tiene sentido. En su lugar, puedes hacer esto:
describe("pageDOM:initializePage", function() { describe("calling initializePage first time", function() { beforeEach(function() { spyOn(pageDOM, "addBoxes"); spyOn(pageDOM, "otherInitProcedures"); }) it("should call both functions", function() { pageDOM.initializePage(); expect(pageDOM.otherInitProcedures).toHaveBeenCalled() expect(pageDOM.addBoxes).toHaveBeenCalled() }) it("should only call otherInitProcedures", function() { pageDOM.initializePage(); expect(pageDOM.otherInitProcedures).toHaveBeenCalled() expect(pageDOM.addBoxes).not.toHaveBeenCalled() }) }) })Jasmine ejecuta los bloques dentro de una descripción secuencialmente y también puede obtener los controles deseados. Enlace de stackblitz en funcionamiento para usted (ignore otros casos de prueba)
Para hacer que el código sea más comprobable, no iniciaría la función de inmediato.
var pageDOMConstructor = vfunction() { var mounted = false return { initializePage: function() { if (mounted == false) { pageDOM.addBoxes(); mount = true } pageDOM.otherInitProcedures(); }, otherFunction: function() { } } }; var pageDOM = pageDOMConstructor(); entonces puedes probar pageDOMConstructor fácilmente. Para verificar con qué frecuencia se ha llamado a algo, puede usar toHaveBeenCalledTimes
esto no está del todo completo y puede necesitar algunos pequeños cambios, es solo para darle una idea de cómo resolver esto:
describe("pageDOMConstructor", function () { describe("initializePage", function () { // setup variable, its a let because it will be reset before every test let pageDom; beforeEach(function () { pageDom = pageDOMConstructor(); spyOn(pageDOM, "addBoxes"); spyOn(pageDOM, "otherInitProcedures"); }); it("should call both functions when calling initializePage first time", function () { pageDOM.initializePage(); expect(pageDOM.otherInitProcedures).toHaveBeenCalledTimes(1); expect(pageDOM.addBoxes).toHaveBeenCalledTimes(1); }); it("should only call otherInitProcedures when calling initializePage again", function () { pageDOM.initializePage(); // you could remove these two lines because they are in the other test expect(pageDOM.otherInitProcedures).toHaveBeenCalledTimes(1); expect(pageDOM.addBoxes).toHaveBeenCalledTimes(1); pageDOM.initializePage(); expect(pageDOM.otherInitProcedures).toHaveBeenCalledTimes(1); expect(pageDOM.addBoxes).not.toHaveBeenCalledTimes(1); }); }); }); Cada it debe tratarse como una prueba separada, y deben ser completamente autosuficientes, con algunas excepciones como beforeEach
Cuando el código es difícil de probar, a menudo es una señal de que podría beneficiarse de refactorizarlo un poco. Descubrí que el código comprobable es igual a un código usable y flexible en producción.