Sinon: withArgs tidak berfungsi dengan baik dengan sinon.mock

Dibuat pada 30 Agu 2017  ·  3Komentar  ·  Sumber: sinonjs/sinon

  • Versi Sinon : 3.2.1
  • Lingkungan: OSX, Node 7
  • Pustaka lain yang Anda gunakan: Mocha, mjackson/expect

Apa yang Anda harapkan terjadi?
Ketika saya membuat tiruan di kelas dan mencoba mengontrol perilaku salah satu fungsinya menggunakan withArgs , pengecualian dilemparkan. Terjadi hanya saat menggunakan beberapa panggilan withArgs .

Apa yang sebenarnya terjadi?

Cara memperbanyak


Contoh yang dapat direproduksi

Asumsikan saya mendeklarasikan kelas C :

      class C {
        static foo(arg1, arg2) {return 'foo';}
      }

Saya mencoba mengontrol perilaku foo menggunakan tiruan pada 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();
      });

Yang melempar pengecualian berikut:

ExpectationError: foo menerima argumen yang salah ["a", "b"], diharapkan ["c", "d"]
di Object.fail (node_modules/sinon/lib/sinon/mock-expectation.js:281:25)
di Fungsi.(node_modules/sinon/lib/sinon/mock-expectation.js:182:33)
di Array.forEach (asli)
di Function.verifyCallAllowed (node_modules/sinon/lib/sinon/mock-expectation.js:175:27)
di Function.invoke (node_modules/sinon/lib/sinon/mock-expectation.js:78:14)
di proxy (node_modules/sinon/lib/sinon/spy.js:89:22)

Sementara kode ini berfungsi:

      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();
      });

Perlu disebutkan bahwa skenario berikut berfungsi seperti yang diharapkan:

      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();
      });

Artinya, masalah hanya terjadi saat menggunakan withArgs beberapa kali.
Ini mungkin terkait dengan #1381, tetapi seperti yang Anda lihat dalam contoh, solusi yang disarankan di sana tidak berfungsi.

Bug Medium Help wanted stale

Komentar yang paling membantu

Saya melihat kodenya.
Pertama-tama, tes ini berfungsi:

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();
});

Ada dua alasan mengapa ini berhasil dan pengujian dalam edisi asli tidak:

  • Saya membuat dua expects .
  • Saya memanggil metode statis alih-alih yang dikembalikan oleh expects .

Artinya, ini juga tidak berfungsi:

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();
});

Mengapa itu terjadi?

Setiap kali expects dipanggil, hal berikut terjadi:

  • Harapan baru (rintisan ditingkatkan dengan minCalls/maxCalls - yang merupakan variabel yang diubah ketika Anda memanggil once() misalnya) dibuat, hanya saja itu adalah "rintisan lingkup", itu tidak memiliki koneksi ke expects . Ini adalah objek yang dikembalikan dari expects .
  • Itu ditambahkan ke daftar harapan.

Yang menghasilkan perilaku berbeda untuk skenario ini:

  • Jika Anda memanggil metode yang dikembalikan oleh expects , itu hanya akan terbatas pada expects .
  • Jika Anda memanggil metode secara langsung dan bukan rintisan, itu akan mencari semua expects dan menemukan satu yang cocok. Jika ada lebih dari satu, itu akan memanggil yang pertama.

Apakah ini perilaku yang benar? Bagi saya lebih intuitif bahwa begitu seseorang memanggil expects pada suatu metode, itu akan berperilaku persis seperti stub (dengan tambahan minCalls/maxCalls ). Ini akan mengakibatkan:

  • Lebih banyak kode dapat dibagikan antara stub dan mock-expectation .
  • Perilaku skenario di atas akan sama.

Sekarang, apa yang akan terjadi pada minCalls/maxCalls ?

Karena hanya ada satu expectation sekarang, saya mengusulkan tiga cara alternatif untuk melakukan verifikasi jumlah panggilan dengan tiruan:

  • Izinkan untuk menggabungkan once() , twice() dll.
  let fooStub = CMock.expects('foo').withArgs('a', 'b').returns(1).twice();
  fooStub.withArgs('c', 'd').returns(2).once(); // Does not affect the previous expectation.

Meskipun mungkin agak membingungkan.

  • Jangan izinkan untuk menggabungkan once() , twice() dll.
  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();

Lebih jelas, tetapi Anda tidak dapat mematikan foo lebih dari sekali sehingga kami memerlukan cara untuk melewatinya. Juga, ini masih mungkin:

  CMock.expects('foo').withArgs('a', 'b').returns(1).withArgs('c', 'd').returns(2).twice(); // I guess that this should only affect the last `withArgs`?
  • Gunakan Spy API yang mengingat jumlah panggilan.

Semua 3 komentar

Terima kasih atas contoh laporan masalah. Saya tidak menggunakan fungsionalitas tiruan, karena itu membuat otak saya sakit, jadi orang lain perlu melihat ini, tetapi contoh Anda akan membuatnya jauh lebih mudah.

Jangan ragu untuk melihat sendiri kodenya - seringkali cara tercepat untuk memperbaikinya :-)

Saya melihat kodenya.
Pertama-tama, tes ini berfungsi:

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();
});

Ada dua alasan mengapa ini berhasil dan pengujian dalam edisi asli tidak:

  • Saya membuat dua expects .
  • Saya memanggil metode statis alih-alih yang dikembalikan oleh expects .

Artinya, ini juga tidak berfungsi:

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();
});

Mengapa itu terjadi?

Setiap kali expects dipanggil, hal berikut terjadi:

  • Harapan baru (rintisan ditingkatkan dengan minCalls/maxCalls - yang merupakan variabel yang diubah ketika Anda memanggil once() misalnya) dibuat, hanya saja itu adalah "rintisan lingkup", itu tidak memiliki koneksi ke expects . Ini adalah objek yang dikembalikan dari expects .
  • Itu ditambahkan ke daftar harapan.

Yang menghasilkan perilaku berbeda untuk skenario ini:

  • Jika Anda memanggil metode yang dikembalikan oleh expects , itu hanya akan terbatas pada expects .
  • Jika Anda memanggil metode secara langsung dan bukan rintisan, itu akan mencari semua expects dan menemukan satu yang cocok. Jika ada lebih dari satu, itu akan memanggil yang pertama.

Apakah ini perilaku yang benar? Bagi saya lebih intuitif bahwa begitu seseorang memanggil expects pada suatu metode, itu akan berperilaku persis seperti stub (dengan tambahan minCalls/maxCalls ). Ini akan mengakibatkan:

  • Lebih banyak kode dapat dibagikan antara stub dan mock-expectation .
  • Perilaku skenario di atas akan sama.

Sekarang, apa yang akan terjadi pada minCalls/maxCalls ?

Karena hanya ada satu expectation sekarang, saya mengusulkan tiga cara alternatif untuk melakukan verifikasi jumlah panggilan dengan tiruan:

  • Izinkan untuk menggabungkan once() , twice() dll.
  let fooStub = CMock.expects('foo').withArgs('a', 'b').returns(1).twice();
  fooStub.withArgs('c', 'd').returns(2).once(); // Does not affect the previous expectation.

Meskipun mungkin agak membingungkan.

  • Jangan izinkan untuk menggabungkan once() , twice() dll.
  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();

Lebih jelas, tetapi Anda tidak dapat mematikan foo lebih dari sekali sehingga kami memerlukan cara untuk melewatinya. Juga, ini masih mungkin:

  CMock.expects('foo').withArgs('a', 'b').returns(1).withArgs('c', 'd').returns(2).twice(); // I guess that this should only affect the last `withArgs`?
  • Gunakan Spy API yang mengingat jumlah panggilan.

Masalah ini secara otomatis ditandai sebagai basi karena tidak ada aktivitas terbaru. Ini akan ditutup jika tidak ada aktivitas lebih lanjut yang terjadi. Terima kasih atas kontribusi Anda.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat