ใช้จัสมินเพื่อสอดแนมฟังก์ชั่นที่ไม่มีวัตถุ


154

ฉันยังใหม่กับจัสมีนและเพิ่งเริ่มใช้มัน ฉันมีไฟล์ไลบรารี js ที่มีฟังก์ชั่นมากมายซึ่งไม่เกี่ยวข้องกับวัตถุใด ๆ (เช่นเป็นระดับโลก) ฉันจะไปสืบเรื่องฟังก์ชันเหล่านี้ได้อย่างไร

ฉันพยายามใช้หน้าต่าง / เอกสารเป็นวัตถุ แต่สายลับไม่ทำงานแม้ว่าจะมีการเรียกใช้ฟังก์ชัน ฉันพยายามห่อด้วยวัตถุปลอมดังนี้:

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

และทดสอบด้วย

expect(fakeElement.fakeMethod).toHaveBeenCalled();

สิ่งนี้ไม่ได้ผลเช่นเดียวกับสายลับไม่ทำงาน

คำตอบ:


155

หากคุณกำหนดหน้าที่ของคุณ:

function test() {};

จากนั้นสิ่งนี้เทียบเท่ากับ:

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

ดังนั้นspyOn(window, 'test')ควรทำงาน

หากไม่เป็นเช่นนั้นคุณควรจะสามารถ:

test = jasmine.createSpy();

หากไม่มีสิ่งใดที่ทำงานได้มีสิ่งอื่นเกิดขึ้นในการตั้งค่าของคุณ

ฉันไม่คิดว่าfakeElementเทคนิคของคุณใช้งานได้เพราะสิ่งที่เกิดขึ้นเบื้องหลัง globalMethod ดั้งเดิมยังคงชี้ไปที่รหัสเดียวกัน การสอดแนมสิ่งที่ทำคือพร็อกซีมัน แต่เฉพาะในบริบทของวัตถุ หากคุณสามารถรับรหัสทดสอบของคุณเพื่อโทรหา FakeElement มันจะใช้งานได้ แต่จากนั้นคุณจะสามารถเลิกใช้ fns ทั่วโลกได้


2
มันได้ผล! ฉันคิดว่าข้อผิดพลาดที่ฉันทำไว้ก่อนหน้านี้คือฉันโทรหา spyOn ด้วย method () แทนที่จะเป็นวิธีการ ขอบคุณ!
Chetter Hummin

3
ฉันมีปัญหาบางอย่างในการใช้ spyOn (window, 'test') โดยใช้ chutzpah เพื่อทำการทดสอบซึ่งเป็นส่วนหนึ่งของระบบอัตโนมัติของเราเนื่องจาก 'window' ไม่ได้รับมอบหมาย ใช้ jasmine.createSpy () ได้รอบนี้
Henners

7
jasmine.createSpy () ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ขอบคุณ!
dplass

1
ใช้test = jasmine.createSpy();ในการสอดแนมใน angularJs $anchroScrollทำงานได้อย่างสมบูรณ์
Edgar Martinez

1
ด้วยเหตุผลบางอย่างฉันไม่สามารถทำงานได้ แต่อาจเป็นไปได้อย่างสิ้นเชิงว่าเป็นเพราะฉันกำลังพยายามเลียนแบบฟังก์ชั่นหน้าต่างที่มีอยู่ $window.open(url, '_blank');ด้วยความตั้งใจที่จะเปิดแท็บใหม่ (หรือหน้าต่างขึ้นอยู่กับการตั้งค่าเบราว์เซอร์) ฉันจะทำอย่างไรเพื่อให้แน่ใจว่ามันกำลังเรียกฟังก์ชั่นนี้และตรวจสอบว่ามันไปยัง URL ที่ถูกต้องโดยไม่คำนึงถึงเบราว์เซอร์?
CSS

71

ผู้ใช้งาน TypeScript:

ฉันรู้ว่า OP ถามเกี่ยวกับจาวาสคริปต์ แต่สำหรับผู้ใช้ TypeScript ที่เจอสิ่งนี้ที่ต้องการสอดแนมในฟังก์ชั่นการนำเข้านี่คือสิ่งที่คุณสามารถทำได้

ในไฟล์ทดสอบแปลงการอิมพอร์ตของฟังก์ชันจากสิ่งนี้:

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

x = foo(y);

สำหรับสิ่งนี้:

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

x = FooFunctions.foo(y);

จากนั้นคุณสามารถสอดแนมFooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();

3
ขอบคุณสำหรับคำใบ้ TypeScript น่าจะเหมือนกันสำหรับ ES6 / Babel แต่ฉันไม่ได้ลองเลย
hgoebl

1
ดูเหมือนว่ามันทำงานได้เฉพาะในกรณีที่เรียกฟังก์ชั่นอย่างชัดเจนกับ FooFunctions ฉันมีแถบฟังก์ชั่น () ซึ่งเป็นโรงงานที่ส่งคืน baz () และต้องการทดสอบว่า baz () เรียก foo () วิธีนี้ดูเหมือนจะไม่ทำงานในสถานการณ์นั้น
Richard Matsen

4
วิธีนี้จะใช้งานได้หากชื่อแทนถูกใช้ภายใน foo_functions export const FooFunctions = { bar, foo }; และการนำเข้าในการทดสอบจะกลายเป็น import { FooFunctions } from '../foo_functions'. อย่างไรก็ตามนามแฝงยังคงต้องใช้อย่างชัดเจนในการดำเนินการส่วนตัวของ foo_functions เพื่อให้สายลับทำงาน const result = FooFunctions.foo(params)// รายงานสายลับโทรconst result = foo(params)// สายลับรายงานไม่มีการโทร
ริชาร์ด Matsen

2
ทำงานเหมือนจับใจ! ขอบคุณคุณช่วยฉันมากเวลา!
SrAxi

1
ไม่ทำงานอีกต่อไปได้รับError: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu

42

มี 2 ​​ทางเลือกที่ฉันใช้ (สำหรับจัสมิน 2)

อันนี้ไม่ค่อยชัดเจนเพราะดูเหมือนว่าฟังก์ชั่นนี้เป็นของปลอม

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

verbose ที่สองชัดเจนยิ่งขึ้นและ "สะอาดกว่า":

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

-> ซอร์สโค้ดจัสมินเพื่อดูอาร์กิวเมนต์ที่สอง


สิ่งนี้สมเหตุสมผลมากขึ้นและแยกออกไปมากพอที่จะทำซ้ำกับความสำเร็จได้ +1 จากฉัน ขอบคุณC§
CSS


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

สิ่งนี้ใช้ได้สำหรับฉัน


4
โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณรหัสนั้นไม่เป็นประโยชน์สำหรับผู้ที่ถามคำถามหากพวกเขาไม่เข้าใจว่าเกิดอะไรขึ้น
chevybow

0

คำตอบของฉันแตกต่างจาก @FlavourScape เล็กน้อยซึ่งฉันมีฟังก์ชั่นเดียว (ส่งออกค่าเริ่มต้น) ในโมดูลที่นำเข้าฉันทำสิ่งต่อไปนี้:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.