क्या चाई को अतुल्यकालिक मोचा परीक्षणों के साथ काम करने का एक तरीका है?


81

मैं ब्राउज़र रनर का उपयोग करते हुए मोचा में कुछ अतुल्यकालिक परीक्षण चला रहा हूं और मैं चाई की अपेक्षित शैली का उपयोग करने की कोशिश कर रहा हूं:

window.expect = chai.expect;
describe('my test', function() {
  it('should do something', function (done) {
    setTimeout(function () {
      expect(true).to.equal(false);
    }, 100);
  }
}

इससे मुझे सामान्य रूप से असफल संदेश नहीं दिया जाता है, इसके बजाय मुझे मिलता है:

Error: the string "Uncaught AssertionError: expected true to equal false" was thrown, throw an Error :)
    at Runner.fail (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3475:11)
    at Runner.uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3748:8)
    at uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3778:10)

तो यह स्पष्ट रूप से त्रुटि को पकड़ रहा है, यह सिर्फ इसे सही ढंग से प्रदर्शित नहीं कर रहा है। कोई जानकारी यह कैसे करनी है? मुझे लगता है कि मैं सिर्फ एक त्रुटि वस्तु के साथ "किया" कह सकता हूं, लेकिन फिर मैं चाय जैसी किसी चीज के सभी लालित्य खो देता हूं और यह बहुत ही स्पष्ट हो जाता है ...


समस्या ब्राउज़र-साइड मोचा के साथ है। इसके बारे में जानकारी के लिए github.com/visionmedia/mocha/pull/278 देखें ।
इलियट फोस्टर

2020 तक, आपको chai-as-promisedप्लगइन पर एक नज़र
डालनी

जवाबों:


96

आपका एसिंक्रोनस परीक्षण एक अपवाद उत्पन्न करता है, असफल expect()परमाणुओं पर, जो कि कब्जा नहीं किया जा सकता है it()क्योंकि अपवाद को it()दायरे से बाहर फेंक दिया जाता है ।

कैप्चर किया गया अपवाद जिसे आप प्रदर्शित करते हैं process.on('uncaughtException'), उसे नोड के तहत या window.onerror()ब्राउज़र में उपयोग करके कैप्चर किया जाता है।

इस समस्या को ठीक करने के लिए, आपको पहले पैरामीटर के रूप में अपवाद के साथ setTimeout()कॉल करने के लिए बुलाया अतुल्यकालिक फ़ंक्शन के भीतर अपवाद को पकड़ने की आवश्यकता है done()। आपको done()सफलता का संकेत देने के लिए किसी पैरामीटर के साथ कॉल करने की आवश्यकता नहीं है, अन्यथा मोचा टाइमआउट त्रुटि की सूचना देगा क्योंकि आपके परीक्षण फ़ंक्शन ने कभी संकेत नहीं दिया होगा कि यह किया गया था:

window.expect = chai.expect;

describe( 'my test', function() {
  it( 'should do something', function ( done ) {
    // done() is provided by it() to indicate asynchronous completion
    // call done() with no parameter to indicate that it() is done() and successful
    // or with an error to indicate that it() failed
    setTimeout( function () {
      // Called from the event loop, not it()
      // So only the event loop could capture uncaught exceptions from here
      try {
        expect( true ).to.equal( false );
        done(); // success: call done with no parameter to indicate that it() is done()
      } catch( e ) {
        done( e ); // failure: call done with an error Object to indicate that it() failed
      }
    }, 100 );
    // returns immediately after setting timeout
    // so it() can no longer catch exception happening asynchronously
  }
}

आपके सभी परीक्षण मामलों पर ऐसा करना कष्टप्रद है न कि DRY ताकि आप ऐसा करने के लिए एक फ़ंक्शन प्रदान करना चाहें। आइए इस फ़ंक्शन को कॉल करें check():

function check( done, f ) {
  try {
    f();
    done();
  } catch( e ) {
    done( e );
  }
}

साथ check()अब आप अपने अतुल्यकालिक परीक्षण इस प्रकार पुनर्लेखन कर सकते हैं:

window.expect = chai.expect;

describe( 'my test', function() {
  it( 'should do something', function( done ) {
    setTimeout( function () {
      check( done, function() {
        expect( true ).to.equal( false );
      } );
    }, 100 );
  }
}

मैंने अपनी पिछली टिप्पणी को हटा दिया था जिसके बाद मुझे एहसास हुआ कि मैं जिस बारे में शिकायत कर रहा था (सेटटाइमआउट) वास्तव में मेरे प्रश्न से था। माफ़ करना!!
थॉमस पारसलो

2
उपरोक्त उत्तर गलत लगता है। एक असफल उम्मीद तुरंत फेंक देगी और एक सार्थक त्रुटि के साथ परीक्षण को रोक देगी, जटिल प्रयास / पकड़ने की कोई आवश्यकता नहीं है। मैंने अभी इसे एक ब्राउज़र परीक्षण के साथ परीक्षण किया है।
ऑफिशो

3
मैं इस मुद्दे से जूझ रहा था और इस ब्लॉग पोस्ट को बेहद मददगार पाया: staxmanade.com/2015/11/…
रिचर्डफ्रायर

1
@ रीचर्डफोरस्टर, बेहद मददगार पोस्ट। धन्यवाद! प्रोमिस के साथ काम करने वाली इस जाँच को प्राप्त करने के लिए कोड को अविश्वसनीय रूप से सरल बनाता है लेकिन यह वादों के साथ होना चाहिए (किसी भी async फ़ंक्शन नहीं)।
पेड्रो आर।

1
बस पश्चाताप के लिए झंकार करना चाहते हैं कि यह सटीक समस्या Vue नेकटिक () (जो वादे के लिए एक आवरण है) के साथ होती है और उसी तरह से संभाला जा सकता है।
एली अल्बर्ट

20

यहाँ ES6 / ES2015 वादों और ES7 / ES2016 async / प्रतीक्षा के लिए मेरे उत्तीर्ण परीक्षण हैं। आशा है कि यह इस विषय पर शोध करने वाले किसी के लिए एक अच्छा अद्यतन उत्तर प्रदान करता है:

import { expect } from 'chai'

describe('Mocha', () => {
  it('works synchronously', () => {
    expect(true).to.equal(true)
  })

  it('works ansyncronously', done => {
    setTimeout(() => {
      expect(true).to.equal(true)
      done()
    }, 4)
  })

  it('throws errors synchronously', () => {
    return true
    throw new Error('it works')
  })

  it('throws errors ansyncronously', done => {
    setTimeout(() => {
      return done()
      done(new Error('it works'))
    }, 4)
  })

  it('uses promises', () => {
    var testPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello')
      }, 4)
    })

    testPromise.then(result => {
      expect(result).to.equal('Hello')
    }, reason => {
      throw new Error(reason)
    })
  })

  it('uses es7 async/await', async (done) => {
    const testPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello')
      }, 4)
    })

    try {
      const result = await testPromise
      expect(result).to.equal('Hello')
      done()
    } catch(err) {
      done(err)
    }
  })

  /*
  *  Higher-order function for use with async/await (last test)
  */
  const mochaAsync = fn => {
    return async (done) => {
      try {
        await fn()
        done()
      } catch (err) {
        done(err)
      }
    }
  }

  it('uses a higher order function wrap around async', mochaAsync(async () => {
    const testPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('Hello')
      }, 4)
    })

    expect(await testPromise).to.equal('Hello')
  }))
})

@ पेड्रो आर। मैं वादे की परीक्षा से हटा दिया गया। जैसा आपने बताया, इसकी जरूरत नहीं है।
रिचर्डफोरर


2

मैंने मोचा मेलिंग सूची में एक ही बात पूछी। उन्होंने मूल रूप से मुझे यह बताया: मोचा और चाय के साथ अतुल्यकालिक परीक्षण लिखने के लिए:

  • हमेशा परीक्षण के साथ शुरू करें if (err) done(err);
  • हमेशा के साथ परीक्षण समाप्त करें done()

इसने मेरी समस्या हल कर दी, और मेरे कोड के बीच (अन्य के बीच चाई ​​अपेक्षाएं) की एक भी लाइन को नहीं बदला। इस setTimoutasync परीक्षण करने का तरीका नहीं है

यहां मेलिंग सूची में चर्चा का लिंक दिया गया है


1
आपके द्वारा लिंक की गई चर्चा सर्वर-साइड चाय और मोचा के बारे में है। पोस्टर ब्राउज़र-साइड मोचा और चाय के बारे में पूछ रहा है
इलियट फोस्टर

यह वही मुद्दा नहीं है। setTimeoutइस सवाल में उदाहरण के रूप में इस्तेमाल किया समारोह अपने कॉलबैक में किसी भी त्रुटि नहीं है।
सिल्वेन बी

1

मैंने एक पैकेज प्रकाशित किया है जो इस मुद्दे को हल करता है।

पहले check-chaiपैकेज स्थापित करें :

npm install --save check-chai

फिर अपने परीक्षणों में, उपयोग करें chai.use(checkChai);और फिर chai.checkनीचे दिखाए अनुसार सहायक फ़ंक्शन का उपयोग करें:

var chai = require('chai');
var dirtyChai = require('dirty-chai');
var checkChai = require('check-chai');
var expect = chai.expect;
chai.use(dirtyChai);
chai.use(checkChai);

describe('test', function() {

  it('should do something', function(done) {

    // imagine you have some API call here
    // and it returns (err, res, body)
    var err = null;
    var res = {};
    var body = {};

    chai.check(done, function() {
      expect(err).to.be.a('null');
      expect(res).to.be.an('object');
      expect(body).to.be.an('object');
    });

  });

});

प्रति असिंच मोचा परीक्षणों के साथ काम करने का एक तरीका है? मैंने इसे एनपीएम पैकेज के रूप में प्रकाशित किया।

अधिक जानकारी के लिए कृपया https://github.com/niftylettuce/check-chai देखें।


1

ChaiAsPromised की कोशिश करो! उत्कृष्ट नाम होने के अलावा, आप इस तरह के बयानों का उपयोग कर सकते हैं:

expect(asyncToResultingValue()).to.eventually.equal(true)

पुष्टि कर सकते हैं , मोचा + ची के लिए बहुत अच्छी तरह से काम करता है।

https://github.com/domenic/chai-as-promised


1

से बहुत अधिक संबंधित और प्रेरित है ज्यां विंसेंट के जवाब , हम उनके कार्य के समान एक सहायक कार्य checkकरते हैं, लेकिन हम इसके eventuallyबजाय इसे कॉल करते हैं (यह चाई-ए-वादा के नामकरण सम्मेलनों के साथ मेल खाने में मदद करता है)। यह एक फ़ंक्शन देता है जो किसी भी संख्या में तर्क लेता है और उन्हें मूल कॉलबैक पर भेजता है। यह आपके परीक्षणों में एक अतिरिक्त नेस्टेड फ़ंक्शन ब्लॉक को खत्म करने में मदद करता है और आपको किसी भी प्रकार के एसिंक्स कॉलबैक को संभालने की अनुमति देता है। यहाँ यह ES2015 में लिखा गया है:

function eventually(done, fn) {
  return (...args) => {
    try {
      fn(...args);
      done();
    } catch (err) {
      done(err);
    }
  };
};

उदाहरण उपयोग:

describe("my async test", function() {
  it("should fail", function(done) {
    setTimeout(eventually(done, (param1, param2) => {
      assert.equal(param1, "foo");   // this should pass
      assert.equal(param2, "bogus"); // this should fail
    }), 100, "foo", "bar");
  });
});

1

मैं जानता हूं कि इसे हल करने के लिए कई रिप्लाई और सुझाए गए पैकेज हैं। हालांकि मैंने ऊपर दिए गए सरल समाधानों को दो उपयोग मामलों के लिए संक्षिप्त पैटर्न नहीं देखा है। मैं इसे कॉपी-पास्ता की इच्छा रखने वाले अन्य लोगों के लिए एक समेकित उत्तर के रूप में पोस्ट कर रहा हूं:

ईवेंट कॉलबैक

function expectEventCallback(done, fn) {
  return function() {
    try { fn(...arguments); }
    catch(error) { return done(error); }
    done();
  };
}

नोड शैली कॉलबैक

function expectNodeCallback(done, fn) {
  return function(err, ...args) {
    if (err) { return done(err); }
    try { fn(...args); }
    catch(error) { return done(error); }
    done();
  };
}

उदाहरण उपयोग

it('handles event callbacks', function(done) {
  something.on('event', expectEventCallback(done, (payload) => {
    expect(payload).to.have.propertry('foo');
  }));
});

it('handles node callbacks', function(done) {
  doSomething(expectNodeCallback(done, (payload) => {
    expect(payload).to.have.propertry('foo');
  }));
});

0

@Richardforrester http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/ द्वारा उपलब्ध कराए गए इस लिंक के आधार पर , वर्णन करें कि यदि आप किया हुआ छोड़ देते हैं तो एक दिए गए वादे का उपयोग कर सकते हैं पैरामीटर।

केवल नीचे की तरफ एक वादा होना चाहिए, न कि किसी भी एस्किंक फंक्शन (आप इसे प्रोमिस, तू के साथ लपेट सकते हैं)। लेकिन इस मामले में, कोड को बहुत कम किया जा सकता है।

यह प्रारंभिक funcThatReturnsAPromise फ़ंक्शन या अपेक्षाओं में से किसी एक में विफलताओं को ध्यान में रखता है:

it('should test Promises', function () { // <= done removed
    return testee.funcThatReturnsAPromise({'name': 'value'}) // <= return added
        .then(response => expect(response).to.have.property('ok', 1));
});

0

मैंने इसे try/catchएक समारोह में निकालने के लिए हल किया ।

function asyncExpect(test, done){
    try{
        test();
        done();
    } catch(error){
        done(error);
    }
}

फिर it()मैं कॉल करता हूं:

it('shall update a host', function (done) {
            testee.insertHost({_id: 'host_id'})
                .then(response => {
                    asyncExpect(() => {
                        expect(response).to.have.property('ok', 1);
                        expect(response).to.have.property('nModified', 1);
                    }, done);
                });

        });

यह डिबेट योग्य भी है।


0

परीक्षण और async के दौरान टाइमर बहुत कठिन लगता है। वादा आधारित दृष्टिकोण के साथ ऐसा करने का एक तरीका है।

const sendFormResp = async (obj) => {
    const result = await web.chat.postMessage({
        text: 'Hello world!',
    });
   return result
}

यह async फ़ंक्शन वेब क्लाइंट का उपयोग करता है (इस मामले में यह स्लैक्स एसडीके है)। एसडीके एपीआई कॉल के अतुल्यकालिक प्रकृति का ख्याल रखता है और एक पेलोड लौटाता है। हम तब expectasync वादे में वापस आ गई वस्तु के खिलाफ चलकर चाय के भीतर पेलोड का परीक्षण कर सकते हैं ।

describe("Slack Logic For Working Demo Environment", function (done) {
    it("Should return an object", () => {
        return sdkLogic.sendFormResp(testModels.workingModel).then(res => {
            expect(res).to.be.a("Object");
        })
    })
});

-2

मेरे लिए बहुत अच्छी तरह से काम किया आइक मोचा / ची सिनॉन लाइब्रेरी से फर्जी था। जहां आवश्यक हो, वहां केवल टाइमर को टेस्ट में एडवांस करें।

var sinon = require('sinon');
clock = sinon.useFakeTimers();
// Do whatever. 
clock.tick( 30000 ); // Advances the JS clock 30 seconds.

परीक्षण पूर्ण होने के साथ जोड़ा बोनस है।


1
मैं निश्चित रूप से अपने आप को ज्यादातर इस तरह के समाधान का उपयोग कर पाया है जब async कोड का परीक्षण। कॉलबैक मोचा होना "अच्छा है" (जैसा कि ऊपर जीन विंसेंट के उत्तर में दिखाया गया है) लेकिन परीक्षण आमतौर पर लिखने में आसान होते हैं जब आप इसका उपयोग नहीं करते हैं।
थॉमस पार्सलो

-2

आप डोमेन मॉड्यूल का भी उपयोग कर सकते हैं। उदाहरण के लिए:

var domain = require('domain').create();

domain.run(function()
{
    // place you code here
});

domain.on('error',function(error){
    // do something with error or simply print it
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.