Menggunakan Jasmine untuk memata-matai suatu fungsi tanpa objek

154

Saya baru mengenal Jasmine dan baru saja mulai menggunakannya. Saya memiliki file perpustakaan js dengan banyak fungsi yang tidak terkait dengan objek apa pun (yaitu global). Bagaimana cara memata-matai fungsi-fungsi ini?

Saya mencoba menggunakan jendela / dokumen sebagai objek, tetapi mata-mata itu tidak berfungsi meskipun fungsinya dipanggil. Saya juga mencoba membungkusnya dengan benda palsu sebagai berikut:

var fakeElement = {};
fakeElement.fakeMethod = myFunctionName;
spyOn(fakeElement, "fakeMethod");

dan tes dengan

expect(fakeElement.fakeMethod).toHaveBeenCalled();

Ini tidak berhasil karena mata-mata tidak bekerja

Chetter Hummin
sumber

Jawaban:

155

Jika Anda mendefinisikan fungsi Anda:

function test() {};

Kemudian, ini setara dengan:

window.test = function() {}  /* (in the browser) */

Jadi spyOn(window, 'test')harusnya bekerja.

Jika tidak, Anda juga harus dapat:

test = jasmine.createSpy();

Jika tidak ada yang berfungsi, ada sesuatu yang terjadi dengan pengaturan Anda.

Saya tidak berpikir fakeElementteknik Anda bekerja karena apa yang terjadi di balik layar. Metode global asli masih menunjuk ke kode yang sama. Yang dilakukan mata-mata adalah proksi itu, tetapi hanya dalam konteks objek. Jika Anda bisa meminta kode pengujian untuk menelepon melalui fakeElement, itu akan berhasil, tetapi kemudian Anda akan bisa memberikan fns global.

ndp
sumber
2
Berhasil! Saya pikir kesalahan yang saya buat sebelumnya adalah bahwa saya memanggil spyOn dengan method () alih-alih metode. Terima kasih!
Chetter Hummin
3
Saya punya beberapa masalah menggunakan spyOn (window, 'test') menggunakan chutzpah untuk menjalankan tes sebagai bagian dari otomatisasi kami karena 'window' tidak ditugaskan. Menggunakan jasmine.createSpy () menyiasati ini.
Henners
7
jasmine.createSpy () bekerja dengan sempurna untuk saya. Terima kasih!
dplass
1
digunakan test = jasmine.createSpy();untuk memata-matai sudut $anchroScrollbekerja dengan sempurna
Edgar Martinez
1
Untuk beberapa alasan saya tidak bisa mendapatkan salah satu cara untuk bekerja, tetapi mungkin sepenuhnya mungkin karena saya mencoba untuk mengejek fungsi jendela yang ada; $window.open(url, '_blank');dengan maksud membuka tab baru (atau jendela tergantung pada pengaturan browser). Bagaimana seharusnya saya memastikan bahwa ia memanggil fungsi ini dan memverifikasi bahwa ia menavigasi ke url yang tepat terlepas dari browser?
CSS
71

Pengguna TypeScript:

Saya tahu OP bertanya tentang javascript, tetapi untuk setiap pengguna TypeScript yang menemukan ini yang ingin memata-matai fungsi yang diimpor, inilah yang dapat Anda lakukan.

Di file uji, konversi impor fungsi dari ini:

import {foo} from '../foo_functions';

x = foo(y);

Untuk ini:

import * as FooFunctions from '../foo_functions';

x = FooFunctions.foo(y);

Maka Anda dapat memata-matai FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();
Alexander Taylor
sumber
3
Terima kasih untuk petunjuk TypeScript. Seharusnya sama untuk ES6 / Babel, tapi saya belum mencobanya.
hgoebl
1
Tampaknya itu hanya berfungsi jika memanggil fungsi secara eksplisit dengan alias FooFunctions . Saya memiliki bilah fungsi () yang merupakan baz pengembalian pabrik () dan ingin menguji baz itu () memanggil foo (). Metode ini tampaknya tidak berfungsi dalam skenario itu.
Richard Matsen
4
Ini akan bekerja jika alias diambil di dalam foo_functions export const FooFunctions = { bar, foo }; dan impor dalam tes menjadi import { FooFunctions } from '../foo_functions'. Namun, alias masih perlu secara eksplisit digunakan dalam implementasi pribadi foo_functions untuk mata-mata untuk bekerja. const result = FooFunctions.foo(params)// laporan mata-mata panggilan const result = foo(params)// mata-mata melaporkan tidak ada panggilan
Richard Matsen
2
Bekerja seperti pesona! Terima kasih, Anda menghemat banyak waktu!
SrAxi
1
Ini tidak berfungsi lagi mendapatError: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu
42

Ada 2 alternatif yang saya gunakan (untuk melati 2)

Yang ini tidak terlalu eksplisit karena tampaknya fungsinya sebenarnya palsu.

test = createSpy().and.callFake(test); 

Yang kedua lebih verbose, lebih eksplisit, dan "bersih":

test = createSpy('testSpy', test).and.callThrough();

-> kode sumber melati untuk melihat argumen kedua

IxDay
sumber
Ini sedikit lebih masuk akal dan memecahkannya cukup jauh untuk diduplikasi dengan kesuksesan. +1 dari saya. Terima kasih, C§
CSS
9

Cara yang sangat sederhana:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');
FlavorScape
sumber
1
import * as saveAsFunctions from 'file-saver';
..........
....... 
let saveAs;
            beforeEach(() => {
                saveAs = jasmine.createSpy('saveAs');
            })
            it('should generate the excel on sample request details page', () => {
                spyOn(saveAsFunctions, 'saveAs').and.callFake(saveAs);
                expect(saveAsFunctions.saveAs).toHaveBeenCalled();
            })

Ini berhasil untuk saya.

Sushil
sumber
4
Harap tambahkan penjelasan pada jawaban Anda, kode itu sendiri tidak membantu orang yang mengajukan pertanyaan jika mereka tidak dapat memahami apa yang sedang terjadi.
chevybow
0

Jawaban saya sedikit berbeda dengan @FlavorScape di mana saya memiliki fungsi tunggal (ekspor standar) dalam modul yang diimpor, saya melakukan hal berikut:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');
IonicBurger
sumber