Mocha / Chai bekle. Atılan hataları yakalamıyor


259

expect.to.throwChai'nin node.js uygulamam için bir testte çalışmasında sorun yaşıyorum . Test atılan hatada başarısız olmaya devam eder, ancak test senaryosunu denemede yakalar ve yakalanan hatayı yakalayıp iddia edersem çalışır.

expect.to.throwDüşündüğüm gibi çalışmıyor mu ?

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();
});

Başarısızlık:

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.

Yanıtlar:


340

Bir işlevi geçmeniz gerekir expect. Bunun gibi:

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.'));

Eğer bunu yapıyor şekilde, geçirerek sonucu çağıran . Ancak bir şeyin atıp atılmadığını test etmek için , kendisine çağrılacak bir işlev geçirmeniz gerekir. Yukarıda kullanılan yöntem arayacak olarak adlandırılan yeni bir işlev oluşturur ile değerine grubu ve birinci bağımsız değişken kümesineexpectmodel.get('z')expectexpectbindmodel.getthismodel'z' .

İyi bir açıklaması buradabind bulunabilir .


Bir işlevi geçtim değil mi? modelörneği beklediğim iletilen / çağrılan get adlı bir işlevi vardır.
doremi

Hayır, yorumunuzu yazarken eklediğim açıklamaya bakın.
Louis

47
Oof. Dokümanlar ( chaijs.com/api/bdd/#throw ) neden bu cilt kullanımını göstermiyor? En yaygın sınama senaryosu to.throw, bir işlev içindeki geçersiz bir durum / bağımsız değişkenlerle çağrılmasını gerektiren belirli bir koşulu sınamaktır. (Bu konuda .... neden chaijs.com'un derin bağlantıları aslında derin bağlantı yok?)
ericsoco

Atmaması gereken bazı parametreleri ilettiğinizde, test yine de bir geçiştir.
Alexandros Spyropoulos

6
Bunun (Eylül 2017 itibariyle) zaman uyumsuz işlevler için işe yaramayacağını unutmayın: bkz. Github.com/chaijs/chai/issues/882#issuecomment-322131680 ve ilgili tartışma.
ChrisV

175

As Bu cevap diyor , ayrıca sadece böyle bir anonim işlevinde kodunuzu sarabilirsiniz:

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

7
Bu, zaman uyumsuz işlev çağrıları için çalışmaz. Diyelim ki model.get vaat döndüren zaman uyumsuzdur. Ancak hata veriyor. Eğer yukarıdaki yaklaşımı denersem, "bitmiş" mocha'ya "bitti" yi bildirmemiz gerektiğinden "zaman aşımına uğrar". Aynı zamanda, bir expect(function(){ model.get('z'); }).to.throw('Property does not exist in model schema.').notify(done); bildirim yöntemi olmadığı için deneyemiyorum .
Anand N

@AnandN Sorununuzu anlarsam, hatayı işlemek için kodunuzu yeniden düzenlemeniz gerekir. Asenkron işlevindeki işlenmemiş hata, gerçek uygulamanızda da bir sorun olmayacak mı?
twiz

2
Cevabınız için teşekkürler twiz. Entegre bir ortamda çalışıyoruz, kullanım modülü istisnaları yakalamaya özen gösteriyor. Yani sorun, birim test senaryolarını çalıştırmaya çalışmamızdır. Sonunda çalışmasını sağlamak için aşağıdaki yaklaşımı kullandık catch (err) { expect(err).equal('Error message to be checked'); done(); }
Anand N

1
Aranacak thisfonksiyonun içinde kullanmanız haricinde iyi bir çözüm . O zaman .bindgitmek için doğru yoldur.
rabbitco

@AnandN Asenkron işlev çağrısı değil atmak o reddetme s. Gelecekte referans olması için, chai-vaat gibi bunu oldukça iyi idare eder.
user5532169

85

Ve zaten ES6 / ES2015 kullanıyorsanız, bir ok işlevi de kullanabilirsiniz. Temelde normal bir anonim işlev kullanmakla aynıdır, ancak daha kısadır.

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

Bununla ilgili bir sorun OLABİLİR çünkü ok fonksiyonları çevreleyen kapsamını alırthis
Eric Hodonsky

1
@Relic Evet, çok doğru. Bu, ok fonksiyonlarının da büyük bir avantajı olabilir. Ok işlevleri this, oluşturuldukları kapsamdan 'miras alır' . Çoğu zaman bind, işlevlerini thisnesnelerine manuel olarak girme ihtiyacını ortadan kaldırdığı için bu bir avantaj olabilir .
Stijn de Witt

@StijndeBu bir avantaj veya dezavantaj değil, kapsam kontrolü ve kasıtlı. Aslında kullanmak için sözdizimi şeker bindve her zaman thisana kapsamına bağlar . Yorumdaki amacım sadece okuyucuların potansiyel bir çukur düşüşünden haberdar olmalarını sağlamaktı.
Eric Hodonsky

1
@Relic Evet, sana katılıyorum. Bir avantaj için kullanılabilir ve bir ok işlevi kullanmak için iyi bir neden olabilir.
Stijn de Witt

75

Bu soru, Chai iddia kütüphanesinden bahsetmeyen sorular da dahil olmak üzere birçok çoğaltmaya sahiptir. Birlikte toplanan temel bilgiler şunlardır:

İddia hemen değerlendirmek yerine işlevi çağırmalıdır.

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

Herhangi bir iddia kütüphanesini kullanarak belirli hataları kontrol edebilirsiniz:

düğüm

  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./)

Meli

  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./)

Chai Beklentisi

  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./);

Testten 'kaçan' istisnaları ele almalısınız

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

Bu başlangıçta kafa karıştırıcı görünebilir. Bisiklete binmek gibi, bir kez tıkladığında sonsuza kadar 'tıklar'.


16

örnekler doc ...;)

çünkü thisbağlama güveniyorsunuz :

  • Bu işlev .throw tarafından çağrıldığında kaybolur
  • bunun ne olması gerektiğini bilmesinin bir yolu yok

şu seçeneklerden birini kullanmanız gerekir:

  • yöntemi veya işlev çağrısını başka bir işlevin içine sarma
  • bağlamı bağlamak

    // 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

Ben de öyle yapıyorum. ES6 uygulamasının açık ara en okunabilir uygulama olduğunu düşünüyorum
relief.melone

1

Bir diğer olası uygulama, .bind () çözümünden daha hantaldır, ancak wait () öğesinin thiskapsanan işleve bağlam sağlayan bir işlev gerektirmesini sağlamaya yardımcı olan bir uygulama call(), örneğin,

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


0

Etrafında güzel bir yol buldum:

// 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);
            }
        })
    })
};

Eski sürümümden çok daha okunabilir:

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
});
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.