Qué esperabas que sucediera?
Cuando creo un simulacro en una clase e intento controlar el comportamiento de una de sus funciones usando withArgs
, se lanza una excepción. Ocurre solo cuando se utilizan varias llamadas de withArgs
.
Que pasa realmente
Como reproducirEjemplo reproducible
Supongamos que declaré una clase C
:
class C {
static foo(arg1, arg2) {return 'foo';}
}
Intento controlar el comportamiento de foo
usando un simulacro en C
:
it('test withArgs mock', () => {
let CMock = sinon.mock(C);
let fooStub = CMock.expects('foo');
fooStub.withArgs('a', 'b').returns(1);
fooStub.withArgs('c', 'd').returns(2);
expect(fooStub('a', 'b')).toEqual(1);
expect(fooStub('c', 'd')).toEqual(2);
CMock.restore();
});
Lo que arroja la siguiente excepción:
ExpectationError: foo recibió argumentos incorrectos ["a", "b"], esperado ["c", "d"]
en Object.fail (node_modules / sinon / lib / sinon / mock-expectation.js: 281: 25)
en función.(módulos_nodo / sinon / lib / sinon / mock-expectation.js: 182: 33)
en Array.forEach (nativo)
en Function.verifyCallAllowed (node_modules / sinon / lib / sinon / mock-expectation.js: 175: 27)
en Function.invoke (node_modules / sinon / lib / sinon / mock-expectation.js: 78: 14)
en el proxy (node_modules / sinon / lib / sinon / spy.js: 89: 22)
Mientras este código funciona:
it('test withArgs stub', () => {
let fooStub = sinon.stub(C, 'foo');
fooStub.withArgs('a', 'b').returns(1);
fooStub.withArgs('c', 'd').returns(2);
expect(fooStub('a', 'b')).toEqual(1);
expect(fooStub('c', 'd')).toEqual(2);
fooStub.restore();
});
Vale la pena mencionar que los siguientes escenarios funcionan como se esperaba:
it('test one withArgs mock', () => {
let CMock = sinon.mock(C);
let fooStub = CMock.expects('foo');
fooStub.withArgs('a', 'b').returns(1);
expect(fooStub('a', 'b')).toEqual(1); // ok
CMock.restore();
});
it('test one withArgs mock', () => {
let CMock = sinon.mock(C);
let fooStub = CMock.expects('foo');
fooStub.withArgs('a', 'b').returns(1);
expect(fooStub('c', 'd')).toEqual(1); // error: foo received wrong arguments ["c", "d"], expected ["a", "b"]
CMock.restore();
});
Es decir, el problema ocurre solo cuando se usa withArgs
varias veces.
Puede estar relacionado con # 1381, pero como puede ver en el ejemplo, la solución sugerida allí no funciona.
Gracias por un informe ejemplar tema. No uso la funcionalidad de simulacros, ya que hace que me duela el cerebro, por lo que alguien más tendrá que echarle un vistazo a esto, pero tus ejemplos deberían facilitarlo mucho.
Siéntase libre de echar un vistazo al código usted mismo, a menudo la forma más rápida de solucionarlo :-)
Eché un vistazo al código.
En primer lugar, esta prueba funciona:
class C {
static foo(arg1, arg2) {return 'foo';}
}
it('test withArgs mock', () => {
let CMock = sinon.mock(C);
CMock.expects('foo').withArgs('a', 'b').returns(1);
CMock.expects('foo').withArgs('c', 'd').returns(2);
expect(C.foo('a', 'b')).toEqual(1);
expect(C.foo('c', 'd')).toEqual(2);
CMock.restore();
});
Hay dos razones por las que esto funciona y la prueba del problema original no:
expects
.expects
.Es decir, esto tampoco funciona:
it('test withArgs mock', () => {
let CMock = sinon.mock(C);
CMock.expects('foo').withArgs('a', 'b').returns(1);
let fooStub = CMock.expects('foo').withArgs('c', 'd').returns(2);
expect(fooStub('a', 'b')).toEqual(1); // Error: foo received wrong arguments ["a", "b"], expected ["c", "d"]
expect(fooStub('c', 'd')).toEqual(2);
CMock.restore();
});
¿Por que sucede?
Cada vez que se llama a expects
, sucede lo siguiente:
minCalls/maxCalls
, que son las variables que se cambian cuando se llama a once()
por ejemplo), solo que es un "código auxiliar con ámbito", no tener conexión con otros expects
. Es el objeto devuelto por expects
.Lo que da como resultado diferentes comportamientos para estos escenarios:
expects
, estará limitado solo a ese expects
.expects
y encontrará uno que se ajuste. Si hay más de uno, llamará al primero.¿Es este el comportamiento correcto? Me parece más intuitivo que una vez que alguien llama a expects
en un método, se comportará exactamente como stub
(con los minCalls/maxCalls
adicionales). Esto resultará en:
stub
y mock-expectation
.Ahora, ¿qué pasaría con minCalls/maxCalls
?
Dado que ahora solo hay un expectation
, propongo tres formas alternativas de realizar la verificación del recuento de llamadas con simulacros:
once()
, twice()
etc. let fooStub = CMock.expects('foo').withArgs('a', 'b').returns(1).twice();
fooStub.withArgs('c', 'd').returns(2).once(); // Does not affect the previous expectation.
Aunque puede ser un poco confuso.
once()
, twice()
etc. CMock.expects('foo').withArgs('a', 'b').returns(1).twice(); // `twice()` returns `null`, so that one has to call `expects()` again to set expectations for other arguments.
CMock.expects('foo').withArgs('c', 'd').returns(2).once();
Es más claro, pero no se puede copiar foo
más de una vez, por lo que necesitaremos una forma de evitarlo. Además, esto todavía es posible:
CMock.expects('foo').withArgs('a', 'b').returns(1).withArgs('c', 'd').returns(2).twice(); // I guess that this should only affect the last `withArgs`?
Este problema se ha marcado automáticamente como obsoleto porque no ha tenido actividad reciente. Se cerrará si no se produce más actividad. Gracias por sus aportaciones.
Comentario más útil
Eché un vistazo al código.
En primer lugar, esta prueba funciona:
Hay dos razones por las que esto funciona y la prueba del problema original no:
expects
.expects
.Es decir, esto tampoco funciona:
¿Por que sucede?
Cada vez que se llama a
expects
, sucede lo siguiente:minCalls/maxCalls
, que son las variables que se cambian cuando se llama aonce()
por ejemplo), solo que es un "código auxiliar con ámbito", no tener conexión con otrosexpects
. Es el objeto devuelto porexpects
.Lo que da como resultado diferentes comportamientos para estos escenarios:
expects
, estará limitado solo a eseexpects
.expects
y encontrará uno que se ajuste. Si hay más de uno, llamará al primero.¿Es este el comportamiento correcto? Me parece más intuitivo que una vez que alguien llama a
expects
en un método, se comportará exactamente comostub
(con losminCalls/maxCalls
adicionales). Esto resultará en:stub
ymock-expectation
.Ahora, ¿qué pasaría con
minCalls/maxCalls
?Dado que ahora solo hay un
expectation
, propongo tres formas alternativas de realizar la verificación del recuento de llamadas con simulacros:once()
,twice()
etc.Aunque puede ser un poco confuso.
once()
,twice()
etc.Es más claro, pero no se puede copiar
foo
más de una vez, por lo que necesitaremos una forma de evitarlo. Además, esto todavía es posible: