मोचा / चाय फेंक दिया त्रुटियों को पकड़ने नहीं expect.to.throw


257

मैं expect.to.throwअपने नोड के लिए एक परीक्षण में काम करने के लिए Chai हो रही मुद्दों कर रहा हूँ । अनुप्रयोग। फेंके गए त्रुटि पर परीक्षण विफल रहता है, लेकिन अगर मैं परीक्षण मामले को लपेटता हूं और पकड़ा गया और पकड़े गए त्रुटि पर जोर देता हूं, तो यह काम करता है।

क्या expect.to.throwऐसा काम नहीं करता जैसा मुझे लगता है कि यह करना चाहिए या कुछ और?

it('should throw an error if you try to get an undefined property', function (done) {
  var params = { a: 'test', b: 'test', c: 'test' };
  var model = new TestModel(MOCK_REQUEST, params);

  // neither of these work
  expect(model.get('z')).to.throw('Property does not exist in model schema.');
  expect(model.get('z')).to.throw(new Error('Property does not exist in model schema.'));

  // this works
  try { 
    model.get('z'); 
  }
  catch(err) {
    expect(err).to.eql(new Error('Property does not exist in model schema.'));
  }

  done();
});

विफलता:

19 passing (25ms)
  1 failing

  1) Model Base should throw an error if you try to get an undefined property:
     Error: Property does not exist in model schema.

जवाबों:


339

आपको एक फ़ंक्शन पास करना होगा expect। ऐशे ही:

expect(model.get.bind(model, 'z')).to.throw('Property does not exist in model schema.');
expect(model.get.bind(model, 'z')).to.throw(new Error('Property does not exist in model schema.'));

जिस तरह से आप कर रहे हैं, आप कॉलिंग expectके परिणाम के लिए गुजर रहे हैं model.get('z')। लेकिन यह परीक्षण करने के लिए कि क्या कुछ फेंक दिया गया है, आपको एक फ़ंक्शन पास करना होगा expect, जो expectखुद को कॉल करेगा। bindऊपर इस्तेमाल की गई विधि एक नया फ़ंक्शन बनाती है जिसे जब कॉल model.getकिया जाता है तो thisसेट के मान के साथ कॉल किया जाएगा modelऔर पहला तर्क सेट किया जाएगा 'z'

का एक अच्छा विवरण यहाँbind पाया जा सकता है


मैंने एक समारोह पास नहीं किया था? modelउदाहरण में एक फ़ंक्शन होता है जिसे मैं प्राप्त करता / करती हूं, जो मुझे उम्मीद में कहा जाता है।
doremi

नहीं, जब आप अपनी टिप्पणी लिख रहे थे, तो मैंने जो स्पष्टीकरण जोड़ा है, उसे देखें।
लुइस

47
ऊफ। डॉक्स ( chaijs.com/api/bdd/#throw ) बाइंड के इस उपयोग को प्रदर्शित क्यों नहीं करते ? के लिए सबसे आम परीक्षण परिदृश्य की तरह लगता है to.throwएक समारोह के भीतर एक विशेष स्थिति का परीक्षण कर रहा है, जिसे अमान्य राज्य / तर्कों के साथ उस फ़ंक्शन को कॉल करने की आवश्यकता होती है। (उस मामले के लिए .... क्यों नहीं chaijs.com के डीपलिंक वास्तव में deeplink?)
ericsoco

जब आप कुछ मापदंडों को पास करते हैं जो फेंकना नहीं चाहिए, तो परीक्षण अभी भी एक पास है।
अलेक्जेंड्रोस स्पाईरोपोलोस

6
ध्यान दें कि यह (सितम्बर 2017 तक) async कार्यों के लिए काम नहीं करेगा: github.com/chaijs/chai/issues/882#issuecomment-322131680 और संबंधित चर्चा देखें।
क्रिस

175

जैसा कि यह उत्तर कहता है , आप अपने कोड को इस तरह एक अनाम फ़ंक्शन में भी लपेट सकते हैं:

expect(function(){
    model.get('z');
}).to.throw('Property does not exist in model schema.');

7
यह एसिंक्रोनस फ़ंक्शन कॉल के लिए काम नहीं कर रहा है। मान लीजिए कि model.get async है जो वादा वापस करता है। हालाँकि यह एक त्रुटि फेंकता है। अगर मैं उपरोक्त दृष्टिकोण की कोशिश करता हूं, तो यह "टाइमिंग आउट" है क्योंकि हमें मोचा को "किया" सूचित करना है। उसी समय, मैं कोशिश नहीं कर सकता expect(function(){ model.get('z'); }).to.throw('Property does not exist in model schema.').notify(done); क्योंकि कोई सूचना विधि नहीं है।
आनंद एन

@AnandN अगर मुझे आपकी समस्या समझ में आती है, तो आपको लगता है कि आपको त्रुटि को संभालने के लिए बस अपने कोड को फिर से भरना होगा। Async फ़ंक्शन में अनहेल्ड त्रुटि क्या आपके वास्तविक ऐप में भी समस्या है?
ट्विज

2
आपके उत्तर के लिए धन्यवाद। हम एक एकीकृत वातावरण में काम कर रहे हैं, मॉड्यूल का उपयोग अपवादों को पकड़ने का ख्याल रखता है। इसलिए, समस्या तब है जब हम इकाई परीक्षण मामलों को चलाने की कोशिश करते हैं। अंत में हमने इसे प्राप्त करने के लिए नीचे दिए गए दृष्टिकोण का उपयोग किया catch (err) { expect(err).equal('Error message to be checked'); done(); }
आनंद एन

1
जब आप thisफ़ंक्शन के अंदर उपयोग कर रहे हैं, तब सिवाय इसके अच्छा समाधान । फिर .bindजाने का सही तरीका है।
खरगोश डे

@AnandN एसिंक्रोनस फ़ंक्शन कॉल फेंक नहीं है , यह s अस्वीकार करता है । भविष्य के संदर्भ के लिए, ची-जैसा-वादा किया गया यह काफी अच्छी तरह से संभालता है।
user5532169

85

और यदि आप पहले से ही ES6 / ES2015 का उपयोग कर रहे हैं तो आप एक तीर फ़ंक्शन का भी उपयोग कर सकते हैं। यह मूल रूप से एक सामान्य अनाम फ़ंक्शन का उपयोग करने के समान है लेकिन कम है।

expect(() => model.get('z')).to.throw('Property does not exist in model schema.');

इसके साथ एक समस्या हो सकती है क्योंकि तीर के कार्य उनके आस-पास के दायरे को लेते हैंthis
एरिक होडोंस्की

1
@Relic हाँ, बहुत सच है। यह तीर के कार्यों का एक बड़ा लाभ भी हो सकता है। तीर का कार्य thisउस दायरे से होता है जहां वे बनाए जाते हैं। अक्सर यह एक फायदा हो सकता है, क्योंकि यह मैन्युअल रूप bindसे उनकी thisवस्तु के लिए कार्य करने की आवश्यकता से बचता है ।
स्टिजन डे विट

@StijndeWitt यह एक फायदा या नुकसान नहीं है, यह गुंजाइश नियंत्रण और जानबूझकर है। यह वास्तव में उपयोग करने के लिए सिंटेक्स चीनी है bindऔर हमेशा thisमाता-पिता के दायरे के लिए बाध्य है । टिप्पणी में मेरा इरादा केवल यह सुनिश्चित करना था कि पाठकों को संभावित गड्ढे गिरने के बारे में पता हो।
एरिक होडोंस्की

1
@Relic हाँ मैं आपसे सहमत हूँ। यह एक लाभ के लिए इस्तेमाल किया जा सकता है और एक तीर समारोह का उपयोग करने के लिए एक अच्छा कारण हो सकता है।
Stijn de Witt

75

इस प्रश्न में कई, कई डुप्लिकेट हैं, जिनमें चाई अभिकथन पुस्तकालय का उल्लेख नहीं करने वाले प्रश्न शामिल हैं। यहां मूल बातें एक साथ एकत्र की गई हैं:

दावे को तुरंत मूल्यांकन करने के बजाय फ़ंक्शन को कॉल करना चाहिए।

assert.throws(x.y.z);      
   // FAIL.  x.y.z throws an exception, which immediately exits the
   // enclosing block, so assert.throw() not called.
assert.throws(()=>x.y.z);  
   // assert.throw() is called with a function, which only throws
   // when assert.throw executes the function.
assert.throws(function () { x.y.z });   
   // if you cannot use ES6 at work
function badReference() { x.y.z }; assert.throws(badReference);  
   // for the verbose
assert.throws(()=>model.get(z));  
   // the specific example given.
homegrownAssertThrows(model.get, z);
   //  a style common in Python, but not in JavaScript

आप किसी भी पुस्तकालय के उपयोग से विशिष्ट त्रुटियों की जांच कर सकते हैं:

नोड

  assert.throws(() => x.y.z);
  assert.throws(() => x.y.z, ReferenceError);
  assert.throws(() => x.y.z, ReferenceError, /is not defined/);
  assert.throws(() => x.y.z, /is not defined/);
  assert.doesNotThrow(() => 42);
  assert.throws(() => x.y.z, Error);
  assert.throws(() => model.get.z, /Property does not exist in model schema./)

चाहिए

  should.throws(() => x.y.z);
  should.throws(() => x.y.z, ReferenceError);
  should.throws(() => x.y.z, ReferenceError, /is not defined/);
  should.throws(() => x.y.z, /is not defined/);
  should.doesNotThrow(() => 42);
  should.throws(() => x.y.z, Error);
  should.throws(() => model.get.z, /Property does not exist in model schema./)

चाई अपेक्षा

  expect(() => x.y.z).to.throw();
  expect(() => x.y.z).to.throw(ReferenceError);
  expect(() => x.y.z).to.throw(ReferenceError, /is not defined/);
  expect(() => x.y.z).to.throw(/is not defined/);
  expect(() => 42).not.to.throw();
  expect(() => x.y.z).to.throw(Error);
  expect(() => model.get.z).to.throw(/Property does not exist in model schema./);

आपको अपवादों को संभालना चाहिए जो परीक्षण से 'बच' जाते हैं

it('should handle escaped errors', function () {
  try {
    expect(() => x.y.z).not.to.throw(RangeError);
  } catch (err) {
    expect(err).to.be.a(ReferenceError);
  }
});

यह पहली बार भ्रामक लग सकता है। बाइक की सवारी की तरह, यह क्लिक करते ही हमेशा के लिए 'क्लिक' कर देता है।


14

डॉक्टर से उदाहरण ...)

क्योंकि आप thisसंदर्भ पर भरोसा करते हैं :

  • जो तब खो जाता है जब फ़ंक्शन को .throw द्वारा आमंत्रित किया जाता है
  • यह जानने वाला नहीं है कि यह क्या होना चाहिए

आपको इनमें से एक विकल्प का उपयोग करना है:

  • किसी अन्य फ़ंक्शन के अंदर विधि या फ़ंक्शन कॉल को लपेटें
  • प्रसंग को बांधें

    // wrap the method or function call inside of another function
    expect(function () { cat.meow(); }).to.throw();  // Function expression
    expect(() => cat.meow()).to.throw();             // ES6 arrow function
    
    // bind the context
    expect(cat.meow.bind(cat)).to.throw();           // Bind

यह है कि मैं यह कैसे करते हैं। मुझे लगता है, द्वारा अब तक का सबसे पठनीय एक है कि ES6 कार्यान्वयन
relief.melone

1

एक अन्य संभावित कार्यान्वयन, .bind () समाधान की तुलना में अधिक बोझिल है, लेकिन एक है जो उस बिंदु को बनाने में मदद करता है जो उम्मीद करता है () को एक फ़ंक्शन की आवश्यकता होती thisहै जो कवर किए गए फ़ंक्शन को एक संदर्भ प्रदान करता है , आप एक का उपयोग कर सकते हैं call(), जैसे,

expect(function() {model.get.call(model, 'z');}).to.throw('...');


0

मुझे इसके आस-पास एक अच्छा रास्ता मिल गया है:

// The test, BDD style
it ("unsupported site", () => {
    The.function(myFunc)
    .with.arguments({url:"https://www.ebay.com/"})
    .should.throw(/unsupported/);
});


// The function that does the magic: (lang:TypeScript)
export const The = {
    'function': (func:Function) => ({
        'with': ({
            'arguments': function (...args:any) {
                return () => func(...args);
            }
        })
    })
};

यह बहुत अधिक पठनीय है तो मेरा पुराना संस्करण:

it ("unsupported site", () => {
    const args = {url:"https://www.ebay.com/"}; //Arrange
    function check_unsupported_site() { myFunc(args) } //Act
    check_unsupported_site.should.throw(/unsupported/) //Assert
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.