jasmine.createSpyObj พร้อมคุณสมบัติ
เมื่อจำลองการอ้างอิงในการทดสอบเชิงมุมของฉันฉันมักจะสร้างวัตถุสอดแนมโดยใช้jasmine.createSpyObj:
const serviceSpy= jasmine.createSpyObj('MyService', ['method']);
จากนั้นให้ไปที่ TestBed:
providers: [
{provide: MyService, useValue: serviceSpy}
]
เมื่อฉันใช้ในการทดสอบฉันสามารถระบุค่าส่งคืนที่ต้องการได้:
serviceSpy.method.and.returnValue(of([...]));
ตอนนี้ฉันต้องล้อเลียนคุณสมบัติด้วยและฉันไม่สามารถหาคำตอบได้ว่ามันควรจะทำอย่างไร createSpyObjไม่อนุญาตให้มีการกำหนดชื่อคุณสมบัติ:
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], ['property']);
แต่ฉันได้ลองใช้วิธีแก้ปัญหาที่แตกต่างกันไปตามบทความและคำตอบมากมายโดยไม่ประสบความสำเร็จเช่น:
// Cannot read property 'and' of undefined
serviceSpy.property.and.returnValue(true);
// not declared configurable
spyOnProperty(serviceSpy, 'property').and.returnValue(true);
// no build errors, but value stays 'undefined'
serviceSpy.property = true;
วิธีเดียวที่ฉันจะทำให้มันทำงานได้ครึ่งหนึ่งคือ:
let fakeValue = true;
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], {'property': fakeValue});
ปัญหาคือมันเป็นการสร้างครั้งเดียว หากฉันต้องการเปลี่ยนค่าที่คาดหวังในการทดสอบก็ไม่ได้ผล
fakeValue = false;
serviceSpy.property ==> stays to the initial value 'true';
มีวิธีแก้ปัญหาทั้งวิธีการจำลองและคุณสมบัติโดยการสร้างวัตถุสอดแนมหรือไม่หรือฉันควรสร้างคลาสปลอมของตัวเองที่ฉันสามารถใช้spyOnและspyOnProperty?
ฉันต้องการทราบด้วยว่าการใช้อาร์เรย์คุณสมบัติในcreateSpyObjคำจำกัดความคืออะไร จนถึงตอนนี้ฉันยังไม่เห็นตัวอย่างใด ๆ บนเว็บที่อธิบายเรื่องนี้
คำตอบ
ตามเอกสาร (เน้นของฉัน):
createSpyObjคุณสามารถสร้างวัตถุสายลับกับหลายคุณสมบัติในการได้อย่างรวดเร็วโดยผ่านอาร์เรย์หรือกัญชาของคุณสมบัติเป็นอาร์กิวเมนต์ที่สามไป ในกรณีนี้คุณจะไม่มีการอ้างอิงถึงสายลับที่สร้างขึ้นดังนั้นหากคุณต้องการเปลี่ยนกลยุทธ์การสอดแนมในภายหลังคุณจะต้องใช้Object.getOwnPropertyDescriptorวิธีการดังกล่าวit("creates a spy object with properties", function() { let obj = createSpyObj("myObject", {}, { x: 3, y: 4 }); expect(obj.x).toEqual(3); Object.getOwnPropertyDescriptor(obj, "x").get.and.returnValue(7); expect(obj.x).toEqual(7); });
คุณสมบัติที่สอดแนมเป็นตัวบอก (ดูเช่นObject.definePropertyใน MDN ) ดังนั้นในการเข้าถึงวัตถุสอดแนมคุณต้องได้รับวัตถุตัวอธิบายจากนั้นโต้ตอบกับgetและsetวิธีการที่กำหนดไว้
ใน TypeScript คอมไพเลอร์ต้องการความช่วยเหลือเล็กน้อย createSpyObjส่งกลับอย่างใดอย่างหนึ่งanyหรือSpyObj<T>และSpyObjเพียงกำหนดวิธีการที่สอดแนม:
type SpyObj<T> = T & {
[K in keyof T]: T[K] extends Func ? T[K] & Spy<T[K]> : T[K];
// | if it's a | spy on it | otherwise leave
// | callable | | it alone
};
ดังนั้นในการเข้าถึง.andgetter ของ descriptor คุณจะต้องมีการผูกมัดตัวเลือก (ตามที่Object.getOwnPropertyDescriptorอาจส่งคืนundefined) และการยืนยันประเภทกับSpy:
(Object.getOwnPropertyDescriptor(obj, "x")?.get as Spy<() => number>).and.returnValue(7);
สนามเด็กเล่น
ขอบคุณมาก @jonrsharpe! ฉันเพิ่งเพิ่มฟังก์ชั่นเพื่อให้ฉันสามารถทำได้:
spyPropertyGetter(spy, 'propName').and.returnValue(...)
ซึ่งกำหนดเป็น:
function spyPropertyGetter(
spyObj: jasmine.SpyObj<any>,
propName: string
) {
return Object.getOwnPropertyDescriptor(spyObj, propName).get as jasmine.Spy<
jasmine.Func
>;
}