Was haben Sie erwartet?
Wenn ich einen Mock für eine Klasse erstelle und versuche, das Verhalten einer ihrer Funktionen mit withArgs
zu steuern, wird eine Ausnahme ausgelöst. Tritt nur auf, wenn mehrere Aufrufe von withArgs
.
Was passiert eigentlich
So reproduzieren SieReproduzierbares Beispiel
Angenommen, ich habe eine Klasse C
deklariert:
class C {
static foo(arg1, arg2) {return 'foo';}
}
Ich versuche, das Verhalten von foo
mit einem Mock auf C
zu kontrollieren:
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();
});
Was die folgende Ausnahme auslöst:
ExpectationError: foo hat falsche Argumente erhalten ["a", "b"], erwartet ["c", "d"]
at Object.fail (node_modules/sinon/lib/sinon/mock-expectation.js:281:25)
bei Funktion.(node_modules/sinon/lib/sinon/mock-expectation.js:182:33)
bei Array.forEach (nativ)
at Function.verifyCallAllowed (node_modules/sinon/lib/sinon/mock-expectation.js:175:27)
at Function.invoke (node_modules/sinon/lib/sinon/mock-expectation.js:78:14)
beim Proxy (node_modules/sinon/lib/sinon/spy.js:89:22)
Während dieser Code funktioniert:
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();
});
Es ist erwähnenswert, dass die folgenden Szenarien wie erwartet funktionieren:
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();
});
Das heißt, das Problem tritt nur auf, wenn withArgs
mehrmals verwendet wird.
Es könnte mit #1381 verwandt sein, aber wie Sie im Beispiel sehen können, funktioniert die dort vorgeschlagene Lösung nicht.
Danke für einen beispielhaften Problembericht . Ich benutze die Mocks-Funktionalität nicht, da sie mein Gehirn verletzt, also muss sich jemand anderes das ansehen, aber Ihre Beispiele sollten das viel einfacher machen.
Schauen Sie sich den Code gerne selbst an - oft der schnellste Weg, dies zu beheben :-)
Ich habe mir den Code angeschaut.
Zunächst funktioniert dieser Test:
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();
});
Es gibt zwei Gründe, warum dies funktioniert und der Test in der ursprünglichen Ausgabe nicht:
expects
.expects
.Das heißt, das funktioniert auch nicht:
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();
});
Warum passiert das?
Jedes Mal, wenn expects
aufgerufen wird, passiert Folgendes:
minCalls/maxCalls
erweiterter Stub - das sind die Variablen, die beispielsweise geändert werden, wenn Sie once()
aufrufen) wird erstellt, nur dass es sich um einen "Scoped-Stub" handelt Verbindung zu anderen expects
. Es ist das von expects
Objekt.Dies führt zu unterschiedlichen Verhaltensweisen für diese Szenarien:
expects
Methode aufrufen, wird sie nur auf diese expects
.expects
und findet eine passende. Wenn es mehr als einen gibt, wird der erste aufgerufen.Ist das das richtige Verhalten? Es scheint mir intuitiver, dass, sobald jemand expects
für eine Methode aufruft, diese sich genau wie ein stub
verhält (mit den zusätzlichen minCalls/maxCalls
). Dies führt zu:
stub
und mock-expectation
.Was würde nun mit minCalls/maxCalls
passieren?
Da es jetzt nur noch ein expectation
, schlage ich drei alternative Möglichkeiten vor, die Anrufanzahl mit Mocks zu überprüfen:
once()
, twice()
usw. zu verketten. let fooStub = CMock.expects('foo').withArgs('a', 'b').returns(1).twice();
fooStub.withArgs('c', 'd').returns(2).once(); // Does not affect the previous expectation.
Könnte aber etwas verwirrend sein.
once()
, twice()
usw. zu verketten. 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();
Klarer, aber Sie können foo
mehr als einmal stoppen, also brauchen wir einen Weg, dies zu umgehen. Auch dies ist weiterhin möglich:
CMock.expects('foo').withArgs('a', 'b').returns(1).withArgs('c', 'd').returns(2).twice(); // I guess that this should only affect the last `withArgs`?
Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivität hatte. Es wird geschlossen, wenn keine weitere Aktivität stattfindet. Vielen Dank für Ihre Beiträge.
Hilfreichster Kommentar
Ich habe mir den Code angeschaut.
Zunächst funktioniert dieser Test:
Es gibt zwei Gründe, warum dies funktioniert und der Test in der ursprünglichen Ausgabe nicht:
expects
.expects
.Das heißt, das funktioniert auch nicht:
Warum passiert das?
Jedes Mal, wenn
expects
aufgerufen wird, passiert Folgendes:minCalls/maxCalls
erweiterter Stub - das sind die Variablen, die beispielsweise geändert werden, wenn Sieonce()
aufrufen) wird erstellt, nur dass es sich um einen "Scoped-Stub" handelt Verbindung zu anderenexpects
. Es ist das vonexpects
Objekt.Dies führt zu unterschiedlichen Verhaltensweisen für diese Szenarien:
expects
Methode aufrufen, wird sie nur auf dieseexpects
.expects
und findet eine passende. Wenn es mehr als einen gibt, wird der erste aufgerufen.Ist das das richtige Verhalten? Es scheint mir intuitiver, dass, sobald jemand
expects
für eine Methode aufruft, diese sich genau wie einstub
verhält (mit den zusätzlichenminCalls/maxCalls
). Dies führt zu:stub
undmock-expectation
.Was würde nun mit
minCalls/maxCalls
passieren?Da es jetzt nur noch ein
expectation
, schlage ich drei alternative Möglichkeiten vor, die Anrufanzahl mit Mocks zu überprüfen:once()
,twice()
usw. zu verketten.Könnte aber etwas verwirrend sein.
once()
,twice()
usw. zu verketten.Klarer, aber Sie können
foo
mehr als einmal stoppen, also brauchen wir einen Weg, dies zu umgehen. Auch dies ist weiterhin möglich: