Чего вы ожидали?
Когда я создаю макет класса и пытаюсь управлять поведением одной из его функций с помощью withArgs
, выдается исключение. Происходит только при использовании нескольких вызовов withArgs
.
Что на самом деле происходит
Как воспроизвестиВоспроизводимый пример
Предположим, я объявил класс C
:
class C {
static foo(arg1, arg2) {return 'foo';}
}
Я пытаюсь контролировать поведение foo
используя имитацию 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();
});
Что вызывает следующее исключение:
ExpectationError: foo получил неверные аргументы ["a", "b"], ожидалось ["c", "d"]
в Object.fail (node_modules / sinon / lib / sinon / mock-expectation.js: 281: 25)
в функции.(node_modules / sinon / lib / sinon / mock-expectation.js: 182: 33)
в Array.forEach (собственный)
в Function.verifyCallAllowed (node_modules / sinon / lib / sinon / mock-expectation.js: 175: 27)
в Function.invoke (node_modules / sinon / lib / sinon / mock-expectation.js: 78: 14)
на прокси (node_modules / sinon / lib / sinon / spy.js: 89: 22)
Пока работает этот код:
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();
});
Стоит отметить, что следующие сценарии работают должным образом:
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();
});
Это означает, что проблема возникает только при многократном использовании withArgs
.
Это может быть связано с # 1381, но, как вы можете видеть в примере, предложенное там решение не работает.
Спасибо за примерный отчет о проблеме. Я не использую имитацию, потому что это причиняет боль моему мозгу, поэтому кому-то еще нужно будет взглянуть на это, но ваши примеры должны сделать это намного проще.
Не стесняйтесь взглянуть на код самостоятельно - часто это самый быстрый способ исправить это :-)
Я взглянул на код.
Прежде всего, этот тест работает:
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();
});
Это работает по двум причинам, а тест в исходном выпуске - нет:
expects
.expects
.Значит, это тоже не работает:
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();
});
Почему это происходит?
Каждый раз, когда вызывается expects
, происходит следующее:
minCalls/maxCalls
- переменные, которые изменяются, когда вы вызываете, например, once()
), только то, что это «заглушка с заданной областью», но не иметь связь с другими expects
. Это объект, возвращенный из expects
.Что приводит к разному поведению для этих сценариев:
expects
, он будет ограничен только этим expects
.expects
и найдет подходящий. Если их несколько, он вызовет первый.Это правильное поведение? Мне кажется более интуитивным, что как только кто-то вызывает expects
для метода, он будет вести себя точно так же, как stub
(с дополнительными minCalls/maxCalls
). Это приведет к:
stub
и mock-expectation
.А что будет с minCalls/maxCalls
?
Поскольку сейчас есть только один expectation
, я предлагаю три альтернативных способа проверки количества вызовов с помощью моков:
once()
, twice()
и т. Д. let fooStub = CMock.expects('foo').withArgs('a', 'b').returns(1).twice();
fooStub.withArgs('c', 'd').returns(2).once(); // Does not affect the previous expectation.
Хотя, возможно, это немного сбивает с толку.
once()
, twice()
и т. Д. 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();
Более ясно, но вы не можете заглушить foo
более одного раза, поэтому нам понадобится способ обойти это. Также это все еще возможно:
CMock.expects('foo').withArgs('a', 'b').returns(1).withArgs('c', 'd').returns(2).twice(); // I guess that this should only affect the last `withArgs`?
Эта проблема была автоматически помечена как устаревшая, поскольку в последнее время не было активности. Он будет закрыт, если больше не будет активности. Спасибо за ваш вклад.
Самый полезный комментарий
Я взглянул на код.
Прежде всего, этот тест работает:
Это работает по двум причинам, а тест в исходном выпуске - нет:
expects
.expects
.Значит, это тоже не работает:
Почему это происходит?
Каждый раз, когда вызывается
expects
, происходит следующее:minCalls/maxCalls
- переменные, которые изменяются, когда вы вызываете, например,once()
), только то, что это «заглушка с заданной областью», но не иметь связь с другимиexpects
. Это объект, возвращенный изexpects
.Что приводит к разному поведению для этих сценариев:
expects
, он будет ограничен только этимexpects
.expects
и найдет подходящий. Если их несколько, он вызовет первый.Это правильное поведение? Мне кажется более интуитивным, что как только кто-то вызывает
expects
для метода, он будет вести себя точно так же, какstub
(с дополнительнымиminCalls/maxCalls
). Это приведет к:stub
иmock-expectation
.А что будет с
minCalls/maxCalls
?Поскольку сейчас есть только один
expectation
, я предлагаю три альтернативных способа проверки количества вызовов с помощью моков:once()
,twice()
и т. Д.Хотя, возможно, это немного сбивает с толку.
once()
,twice()
и т. Д.Более ясно, но вы не можете заглушить
foo
более одного раза, поэтому нам понадобится способ обойти это. Также это все еще возможно: