Mocha ve chai ile vaatleri doğru bir şekilde nasıl test ederim?


152

Aşağıdaki test tuhaf davranıyor:

it('Should return the exchange rates for btc_ltc', function(done) {
    var pair = 'btc_ltc';

    shapeshift.getRate(pair)
        .then(function(data){
            expect(data.pair).to.equal(pair);
            expect(data.rate).to.have.length(400);
            done();
        })
        .catch(function(err){
            //this should really be `.catch` for a failed request, but
            //instead it looks like chai is picking this up when a test fails
            done(err);
        })
});

Reddedilmiş bir sözü nasıl düzgün bir şekilde ele almalı (ve test etmeliyim)?

: Nasıl düzgün yani (başarısız bir testi ele olmalıdır expect(data.rate).to.have.length(400);?

İşte test ettiğim uygulama:

var requestp = require('request-promise');
var shapeshift = module.exports = {};
var url = 'http://shapeshift.io';

shapeshift.getRate = function(pair){
    return requestp({
        url: url + '/rate/' + pair,
        json: true
    });
};

Yanıtlar:


236

Yapılması en kolay şey, Mocha'nın son sürümlerinde sahip olduğu yerleşik vaatleri kullanmaktır:

it('Should return the exchange rates for btc_ltc', function() { // no done
    var pair = 'btc_ltc';
    // note the return
    return shapeshift.getRate(pair).then(function(data){
        expect(data.pair).to.equal(pair);
        expect(data.rate).to.have.length(400);
    });// no catch, it'll figure it out since the promise is rejected
});

Veya modern Node ve async / await ile:

it('Should return the exchange rates for btc_ltc', async () => { // no done
    const pair = 'btc_ltc';
    const data = await shapeshift.getRate(pair);
    expect(data.pair).to.equal(pair);
    expect(data.rate).to.have.length(400);
});

Bu yaklaşım uçtan uca vaatler olduğundan, test etmek daha kolaydır ve done()her yerdeki garip çağrılar gibi düşündüğünüz garip vakaları düşünmek zorunda kalmazsınız .

Bu, Mocha'nın şu anda Jasmine gibi diğer kütüphanelere göre bir avantajı. Ayrıca Chai As Promised'ı kontrol etmek isteyebilirsiniz, bu da işi daha da kolaylaştırır (hayır .then) ama şahsen ben mevcut sürümün netliğini ve basitliğini tercih ederim.


4
Bu, Mocha'nın hangi sürümünde başladı? Bunu Ensure the done() callback is being called in this testmocha 2.2.5 ile yapmaya çalışırken bir hata alıyorum.
Scott

14
@Scott , bunu devre dışı bırakacak bir doneparametre almayın it.
Benjamin Gruenbaum

2
Bu bana çok yardımcı oldu. Çıkarma donebenim de itcallback'inde ve açıkça çağrıda returngeri arama (sözünü) Ben sadece kod parçacığının gibi çalışan sınıfın var nasıl.
Kullanıcı 1058612

5
Harika cevap, mükemmel çalışıyor. Dokümanlara dönüp baktığımda, orada - sanırım kaçırmak kolay. Alternately, instead of using the done() callback, you may return a Promise. This is useful if the APIs you are testing return promises instead of taking callbacks:
Federico

4
Scott ile aynı sorunu yaşıyorum. Çağrıya bir doneparametre it

44

Zaten işaret burada , Mocha yeni sürümleri zaten Promise-farkındadır. Ancak OP özellikle Chai hakkında soru sorduğundan, chai-as-promisedvaatleri test etmek için temiz bir sözdizimi sağlayan paketi belirtmek doğru olur :

söz verildiği gibi chai kullanmak

Burada Chai-söz olarak test hem kullanabileceğiniz nasıl resolveve rejectbir Promise durumlarda:

var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);

...

it('resolves as promised', function() {
    return expect(Promise.resolve('woof')).to.eventually.equal('woof');
});

it('rejects as promised', function() {
    return expect(Promise.reject('caw')).to.be.rejectedWith('caw');
});

söz verildiği gibi chai olmadan

Neyin test edildiğini gerçekten açıklığa kavuşturmak için, burada söz verildiği gibi chai olmadan kodlanmış aynı örnek var:

it('resolves as promised', function() {
    return Promise.resolve("woof")
        .then(function(m) { expect(m).to.equal('woof'); })
        .catch(function(m) { throw new Error('was not supposed to fail'); })
            ;
});

it('rejects as promised', function() {
    return Promise.reject("caw")
        .then(function(m) { throw new Error('was not supposed to succeed'); })
        .catch(function(m) { expect(m).to.equal('caw'); })
            ;
});

6
İkinci yaklaşımla ilgili sorun catch, expect(s)başarısızlardan biri başarısız olduğunda ortaya çıkmasıdır. Bu, söz vermemesine rağmen başarısız olduğu izlenimini veriyor. Başarısız olan tek beklentidir.
TheCrazyProgrammer

3
Takmak için aramam gerektiğini söylediğin için çok teşekkürler Chai.use. Bunu ellerinde bulunan belgelerden asla anlamazdım. | :(
Arcym

3

İşte benim almam:

  • kullanma async/await
  • ekstra chai modüllerine gerek yok
  • yakalama sorunundan kaçınarak, @TheCrazyProgrammer yukarıda belirtti

0 gecikme verildiğinde başarısız olan gecikmiş bir vaat fonksiyonu:

const timeoutPromise = (time) => {
    return new Promise((resolve, reject) => {
        if (time === 0)
            reject({ 'message': 'invalid time 0' })
        setTimeout(() => resolve('done', time))
    })
}

//                     ↓ ↓ ↓
it('promise selftest', async () => {

    // positive test
    let r = await timeoutPromise(500)
    assert.equal(r, 'done')

    // negative test
    try {
        await timeoutPromise(0)
        // a failing assert here is a bad idea, since it would lead into the catch clause…
    } catch (err) {
        // optional, check for specific error (or error.type, error. message to contain …)
        assert.deepEqual(err, { 'message': 'invalid time 0' })
        return  // this is important
    }
    assert.isOk(false, 'timeOut must throw')
    log('last')
})

Pozitif test oldukça basittir. 500→0Reddedilen söz yükseldiğinden, beklenmeyen başarısızlık (simüle etme ) testi otomatik olarak başarısız olur.

Negatif test , deneme-yakalama fikrini kullanır. Ancak: istenmeyen bir geçiş hakkında 'şikayet etme', yalnızca catch cümlesinden sonra gerçekleşir (bu şekilde, catch () cümlesinde bitmez, daha fazla ancak yanıltıcı hataları tetikler.

Bu stratejinin çalışması için, testi catch cümlesinden döndürmek gerekir. Başka bir şeyi test etmek istemiyorsanız, başka bir it () - blok kullanın.


2

Bu daha iyi bir çözüm. Sadece bir catch bloğunda yapılan hatayı döndür.

// ...

it('fail', (done) => {
  // any async call that will return a Promise 
  ajaxJson({})
  .then((req) => {
    expect(1).to.equal(11); //this will throw a error
    done(); //this will resove the test if there is no error
  }).catch((e) => {
    done(e); //this will catch the thrown error
  }); 
});

bu test aşağıdaki mesajla başarısız olacaktır: AssertionError: expected 1 to equal 11

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.