Sinon: Sandbox melempar kesalahan 'tidak dapat menghentikan properti milik yang tidak ada'

Dibuat pada 18 Agu 2017  ·  14Komentar  ·  Sumber: sinonjs/sinon

Saya baru saja mencoba meningkatkan dari 2.4.1 ke 3.2.1 dan mengalami masalah berikut. Kode ini berfungsi di 2.4.1:

        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });

Tapi di 3.2.1 itu melontarkan pengecualian: TypeError: Cannot stub non-existent own property google

Itu tidak disebutkan dalam panduan migrasi sehingga tampaknya ini regresi.

Bug Regression

Komentar yang paling membantu

~ Terima kasih telah memulihkan perilaku ini. ~

Ingin menambahkan kasus penggunaan yang mendukung stubbing properti nonexistint.

Dalam kasus penggunaan saya, saya menghentikan properti pada objek konfigurasi. Objek config memiliki berbagai kunci opsional, dan diinisialisasi dengan memuat file dari mesin pengembang. Saat saya menjalankan pengujian tertentu, saya memerlukan salah satu kunci tersebut disetel ke nilai yang diketahui, dan kemudian ingin memulihkan objek pengembang seperti semula.

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) adalah cara yang sangat jelas untuk menyampaikan hal ini. Ada baiknya saya mendapatkan perilaku yang sama, _ meskipun saya tidak tahu pada waktu proses apakah kuncinya disetel_ atau tidak.

Semua 14 komentar

Terkait dengan # 1512.

Jika properti tidak ada, Anda tidak perlu menambahkannya ke kotak pasir. Cukup timpa saja. Tapi ya, jika itu berhasil sebelumnya, dan kami belum secara eksplisit mengatakan itu harus berubah, maka itu regresi.

Tidak yakin apa yang harus kami lakukan di sini. Perbarui dokumen untuk mengatakan bahwa mematikan nilai yang tidak ada tidak masuk akal dan tidak didukung, atau membuatnya mungkin?

Jika properti tidak ada, Anda tidak perlu menambahkannya ke kotak pasir. Cukup timpa saja.

Hal yang menyenangkan tentang menambahkan properti ke kotak pasir adalah sinon kemudian membantu saya menjaga lingkungan pengujian global saya tetap bersih di antara setiap pengujian melalui sandbox.restore() . Ini adalah fitur yang sangat berguna, terutama saat berurusan dengan pustaka pihak ketiga seperti Google Maps di mana saya tidak mengontrol API. Akan lebih bagus jika itu bisa dibuat untuk bekerja di baris 3.x.

Saya juga baru menyadari bahwa saya melakukan dosa karena tidak memberikan contoh yang lengkap. Sandbox saya sedang dibuat dengan format 2.4.1:

let sandbox;

before(() => { sandbox = sinon.sandbox.create(); })
afterEach(() => { sandbox.restore(); })

Tidak yakin apakah itu penting; maaf karena tidak memberikannya lebih awal.

Saya pikir dalam skenario seperti yang dijelaskan @ZebraFlesh , saya lebih suka perlengkapan teks lebih eksplisit.

// not so explicit, doesn't work with [email protected]
beforeEach(function() {
    const spy = sandbox.spy();
    sandbox.stub(window, 'google').value({
        maps: {
            LatLng: x => x,
            Map: spy
        }
    }); 
});
// more explicit, works with sinon<strong i="9">@2</strong>, sinon<strong i="10">@3</strong>
function setGoogleMapsFixture(sandbox) {
    window.google = {
        maps: {
            LatLng: x => x,
            Map: sandbox.spy()
        }
    };
}

function removeGoogleMapsFixture() {
    delete window.google;
}

beforeEach(function() {
    setGoogleMapsFixture(sandbox)
});

// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
    removeGoogleMapsFixture();
});

Dengan pengaturan fixture yang lebih eksplisit seperti yang diuraikan di atas, Anda tidak memerlukan fitur di Sinon yang akan memungkinkan penghentian properti yang tidak ada.

Tidak yakin apa yang harus kami lakukan di sini. Perbarui dokumen untuk mengatakan bahwa mematikan nilai yang tidak ada tidak masuk akal dan tidak didukung, atau membuatnya mungkin?

Meskipun saya menyadari bahwa ini mungkin nyaman dalam beberapa skenario (seperti yang dijelaskan oleh @ZebraFlesh), saya pikir bahwa mematikan properti yang tidak ada sendiri kemungkinan besar akan menyebabkan kesalahan dalam pengujian, di mana pengujian tersebut berhasil karena penulis salah mengetik nama dari properti yang ada yang ingin mereka rintis. Kita harus berusaha untuk menghilangkan kemungkinan kesalahan jika kita bisa tanpa terlalu membatasi.

Saya pikir penonaktifan properti yang tidak ada harus tetap tidak didukung. Kami harus memperbarui dokumentasi.

@mroderick Saya setuju dengan Anda bahwa ini mungkin membuat lebih sedikit bug, tetapi kami sudah mendukung ini untuk stub normal. Jika kita harus berhenti mendukung perilaku ini, kita perlu menghapusnya juga, agar konsisten. Aneh jika hanya mendukung fitur ini di luar kotak pasir, karena kotak pasir biasanya _add_ beberapa kemungkinan. Dan mencopot penyangga adalah fitur yang merusak, jadi diperlukan perubahan besar juga.

Jadi:

  • hapus centang segera untuk kotak pasir untuk memperbaiki fitur yang merusak ini

atau dan(?)

  • hapus fungsionalitas untuk stub normal dan sandbox

    • rilis versi utama baru dengan dokumen yang diperbarui

Dengan pengaturan fixture yang lebih eksplisit seperti yang diuraikan di atas, Anda tidak memerlukan fitur di Sinon yang akan memungkinkan penghentian properti yang tidak ada.

Saya pikir itu berfungsi dengan baik jika perlengkapan Anda tidak pernah bervariasi di antara tes Anda. Namun, perlengkapan saya melakukannya. Contoh sederhana mencakup kasus sukses dan kegagalan:

it('handles the success case', () => {
        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });
        // ... test, including asserting that the spy was called
});

it('handles the failure case', () => {
        const msg = 'test error';
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: sandbox.stub().throws(new Error(msg))
            }
        });
        // ... test, ignoring spy calls and instead focusing on error handling
});

Perilaku di 2.x memiliki keuntungan karena semuanya dibersihkan dengan benar setelah setiap pengujian melalui sandbox.restore() . Menggunakan contoh penyiapan perlengkapan yang lebih eksplisit yang diuraikan di atas, saya kira Anda dapat menghapus properti bukan milik sendiri di hook afterEach untuk mencapai efek yang sama.

Untuk mengatasi masalah memperkenalkan potensi kesalahan dengan secara tidak sengaja mengetik nama properti yang sudah ada, sinon dapat memodifikasi API publik:

  • stub.ownValue() : stub hanya memiliki properti sendiri, melempar untuk properti yang bukan milik sendiri
  • stub.value() : hanya bertopik properti yang bukan milik sendiri, melempar untuk properti sendiri

API menjadi lebih eksplisit dan konsumen dipaksa untuk memilih alat yang sesuai untuk tugas yang ada.

Ini sangat terkait dengan pembahasan di # 1508 (meskipun berhubungan dengan stub normal) h, di mana @lucasfcosta memiliki pandangan yang berlawanan - bahwa kami _harus membuang_ untuk properti undefined . Apa pun tempat kami mendarat, saya sangat yakin _kita harus konsisten_ dalam stubbing API untuk stub dan sandbox normal. Kita seharusnya tidak mendukungnya dalam satu kasus, dan bukan yang lain.

Sekarang, situasinya adalah:

  • rintisan normal digunakan untuk melempar 1.x, tapi ini berubah di 2.0 dan tidak membuang sekarang lagi
  • kotak pasir tidak digunakan untuk melempar, tetapi mulai melempar 3.1 (?)

Jadi untuk sementara kami memiliki kesamaan fitur, tetapi kemudian kami kehilangannya lagi ... Saya tidak berpikir zig-zag ini sangat bermanfaat bagi pengguna, jadi kami harus memulai diskusi ini. Meskipun saya setuju dengan Morgan karena mungkin membuat pengujian yang lebih spesifik, saya tidak suka menghapus perilaku untuk dua rilis utama, lalu menambahkannya kembali. Saya pikir itu akan membuat kebisingan paling sedikit (perbaikan untuk klien, pertanyaan / masalah pada pelacak ini) hanya untuk mengembalikan regresi ini.

Meskipun saya memahami ketidaknyamanan ini, sepertinya ada solusi mudah dengan sedikit perubahan kode.

before(function() {
  window.google = 'This is a placeholder for sinon to overwrite.';
});

after(function() {
  delete window.google;
});

Ini memungkinkan kode sinon tetap tidak berubah.

Regresi vs dokumentasi yang buruk

Ini tampaknya perilaku yang diharapkan karena ada tes untuk itu. Kami harus memperbarui dokumen untuk mencerminkan pendapat saya. Itu datang secara besar-besaran sehingga perubahan yang melanggar ditoleransi.

@fearphage Mempertahankan status quo berarti menghentikan bidang yang tidak ada adalah perilaku yang tidak didukung untuk kotak pasir, sementara itu mendukung perilaku untuk stub normal. Tidakkah sedikit disayangkan bahwa kedua set fitur tidak selaras?

Resolusi diterapkan di # 1557

Saya telah membaca berbagai utas dan saya dapat melihat mengapa ini terjadi, tetapi itu sangat menyakitkan dalam Ketikan di mana Anda sering mendapatkan fungsi yang diimplementasikan pada prototipe kelas, dalam hal ini sinon meludah dummy meskipun semuanya terlihat baik-baik saja bijaksana (karena keyof YourType akan dengan senang hati mengizinkan semua fungsi publik yang didefinisikan lebih jauh di rantai prototipe).

Saya mendapatkan bahwa Typecript mungkin bukan prioritas bagi kalian, tetapi bahkan di JS tampaknya berlawanan dengan intuisi bahwa myObject.callMe() akan dieksekusi dengan senang hati, sementara sinon.stub(myObject, "callMe") tidak dalam kasus itu. Saya lebih suka untuk tidak pergi dan menyelidiki bagaimana objek tertentu itu disatukan supaya saya tahu bagaimana cara menghentikannya.

Saya benar-benar berpikir ini adalah kasus penggunaan yang penting untuk membuat jalur yang menyenangkan, mengingat kelas mendapatkan lebih banyak dukungan asli di JS.

Jika Anda mendapatkan kesalahan yang mengatakan bahwa metode tersebut tidak ditentukan pada objek, Anda tahu bahwa kesalahan tersebut mungkin pada prototipe. Kemudian secara langsung memodifikasi objek menggunakan myObject.callMe = sinon.stub(); sepertinya tidak terlalu merepotkan IMHO ... Seharusnya juga menyelamatkan Anda dari membuat fungsi pembersihan / pembongkaran, karena prototipe tidak pernah diubah.

Ya, saya kira itu tidak terlalu sulit untuk diselesaikan, itu hanya memberi lebih banyak beban kognitif pada saya untuk menyadari bagaimana hal-hal diimplementasikan.

Itu juga sepertinya tidak terduga, sehingga saya merasa perlu menambahkan komentar dalam pengujian untuk menjelaskan mengapa kode stubbing pada 2 baris berturut-turut untuk objek yang sama berbeda, dan mengapa saya secara manual menghapus salah satu stub di teardown saya, tapi yang lainnya ditangani oleh kotak pasir.

~ Terima kasih telah memulihkan perilaku ini. ~

Ingin menambahkan kasus penggunaan yang mendukung stubbing properti nonexistint.

Dalam kasus penggunaan saya, saya menghentikan properti pada objek konfigurasi. Objek config memiliki berbagai kunci opsional, dan diinisialisasi dengan memuat file dari mesin pengembang. Saat saya menjalankan pengujian tertentu, saya memerlukan salah satu kunci tersebut disetel ke nilai yang diketahui, dan kemudian ingin memulihkan objek pengembang seperti semula.

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) adalah cara yang sangat jelas untuk menyampaikan hal ini. Ada baiknya saya mendapatkan perilaku yang sama, _ meskipun saya tidak tahu pada waktu proses apakah kuncinya disetel_ atau tidak.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat