ماذا تتوقع أن يحدث؟
عندما أقوم بإنشاء محاكاة للفصل ومحاولة التحكم في سلوك إحدى وظائفه باستخدام 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();
});
مما يطرح الاستثناء التالي:
خطأ توقع: تلقي foo وسيطات خاطئة ["أ" ، "ب"] ، متوقع ["ج" ، "د"]
في Object.fail (node_modules / sinon / lib / sinon / mock-المتوقعة.js: 281: 25)
في الوظيفة.(node_modules / sinon / lib / sinon / mock-المتوقعة.js: 182: 33)
في Array.forEach (أصلي)
في Function.verifyCallAllowed (node_modules / sinon / lib / sinon / mock-المتوقعة.js: 175: 27)
في Function.invoke (node_modules / sinon / lib / sinon / mock-المتوقعة.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 ، ولكن كما ترى في المثال ، فإن الحل المقترح هناك لا يعمل.
شكرا لتقرير المشكلة النموذجي . لا أستخدم وظيفة mocks ، لأنها تجعل عقلي يؤلمني ، لذلك سيحتاج شخص آخر إلى إلقاء نظرة على هذا ، ولكن أمثلةك ستجعل ذلك أسهل كثيرًا.
لا تتردد في إلقاء نظرة على الكود بنفسك - غالبًا ما تكون أسرع طريقة لإصلاح هذا :-)
ألقيت نظرة على الكود.
بادئ ذي بدء ، يعمل هذا الاختبار:
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
واحد فقط الآن ، أقترح ثلاث طرق بديلة لإجراء التحقق من عدد المكالمات باستخدام mocks:
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
واحد فقط الآن ، أقترح ثلاث طرق بديلة لإجراء التحقق من عدد المكالمات باستخدام mocks:once()
،twice()
إلخ.قد يكون محيرا بعض الشيء بالرغم من ذلك.
once()
،twice()
إلخ.أكثر وضوحًا ، لكن لا يمكنك إيقاف
foo
أكثر من مرة ، لذا سنحتاج إلى طريقة لتجاوز ذلك. أيضًا ، لا يزال هذا ممكنًا: