गुणों के साथ jasmine.createSpyObj

Oct 28 2020

जब मेरे कोणीय परीक्षणों में निर्भरता का मजाक उड़ाया जाता है, तो मैं आमतौर पर एक जासूसी वस्तु का उपयोग करता हूं 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परिभाषा में गुण सरणी का उपयोग क्या है । अब तक मैंने इसे समझने वाले वेब पर कोई उदाहरण नहीं देखा है।

जवाब

5 jonrsharpe Oct 28 2020 at 01:29

प्रति प्रलेखन (जोर मेरा):

आप तीसरे तर्क के रूप में एक सरणी या हैश के गुणों को पास करके उस पर कई गुणों के साथ एक जासूसी वस्तु बना सकते हैं 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पर उदाहरण देखें ), इसलिए जासूस ऑब्जेक्ट को प्राप्त करने के लिए आपको विवरणकर्ता ऑब्जेक्ट प्राप्त करने की आवश्यकता है और फिर उस पर परिभाषित तरीकों getऔर setतरीकों के साथ बातचीत करें ।


टाइपस्क्रिप्ट में, कंपाइलर को थोड़ी मदद की ज़रूरत होती है। या 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
};

इसलिए .andडिस्क्रिप्टर के गेट्टर पर पहुंचने के लिए , आपको वैकल्पिक चैनिंग की आवश्यकता होगी (जैसा Object.getOwnPropertyDescriptorकि वापसी हो सकती है undefined) और इसके लिए एक प्रकार का दावा करना होगा Spy:

(Object.getOwnPropertyDescriptor(obj, "x")?.get as Spy<() => number>).and.returnValue(7);

खेल का मैदान

1 IanGrainger Nov 11 2020 at 17:57

बहुत बहुत शुक्रिया @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
  >;
}