Yasemin'de bir hata atılmasını bekleyen bir test nasıl yazılır?


490

Bir hata bekliyor Jasmine Test Framework için bir test yazmaya çalışıyorum . Şu anda GitHub'dan bir Jasmine Node.js entegrasyonu kullanıyorum .

Düğüm modülümde şu kod var:

throw new Error("Parsing is not possible");

Şimdi bu hatayı bekleyen bir test yazmaya çalışıyorum:

describe('my suite...', function() {
    [..]
    it('should not parse foo', function() {
    [..]
        expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));
    });
});

Ayrıca Error()ve diğer bazı varyantları denedim ve nasıl çalıştığını anlayamıyorum.


4
Anonim bir işlev kullanmadan test edilen işleve argümanlar iletmek için şunu deneyin Function.bind: stackoverflow.com/a/13233194/294855
Danyal Aytekin

Yanıtlar:


802

expect(...)çağrıya bir fonksiyon geçiriyor olmalısınız . Burada sahip olduğunuz kod:

// incorrect:
expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));

aslında çalışıyor çağrı parser.parse(raw) içine geçmesi sonucunu bir girişim expect(...),

Bunun yerine anonim bir işlev kullanmayı deneyin:

expect( function(){ parser.parse(raw); } ).toThrow(new Error("Parsing is not possible"));

28
Eğer çok argümanları geçmesi gerekmez, ayrıca sadece beklemek işlevini geçirebilirsiniz:expect(parser.parse).toThrow(...)
SubmittedDenied

60
Yararlı ipucu: Sadece arayabilirsiniz expect(blah).toThrow(). Hiçbir argüman, atıp atmadığını kontrol etmek anlamına gelir. Dize eşleşmesi gerekmez. Ayrıca bakınız: stackoverflow.com/a/9525172/1804678
Jess

1
Bence, anonim bir fonksiyonda sararken testin amacına göre daha açıktır. Ayrıca, örneğin, atmak için parametreleri hedef fonksiyona iletmeniz gerektiğinde tüm testler arasında tutarlı kalır.
Beez

10
@SubmissionDenied: Bu genel olarak çalışmıyor! Eğer parser.parsekullanımlar this, bağlam olmadan geçen beklenmeyen sonuçlar üretecektir. Geçebilirsin parser.parse.bind(parser), ama dürüstçe ... anonim bir işlev daha zarif olurdu.
mhelvens

2
@LanceKind necro için özür dileriz, ancak bir işlevi geçmek zorunda olmanızın nedeni, bir değerin değerlendirilmesinin ve beklemeye bile geçmeden önce bir istisna atmasıdır.
1gLassitude

68

Kullanıyorsun:

expect(fn).toThrow(e)

Ancak işlev yorumuna bir göz atacaksanız (beklenen dizedir):

294 /**
295  * Matcher that checks that the expected exception was thrown by the actual.
296  *
297  * @param {String} expected
298  */
299 jasmine.Matchers.prototype.toThrow = function(expected) {

Sanırım muhtemelen böyle yazmalısınız (lambda - anonim işlev kullanarak):

expect(function() { parser.parse(raw); } ).toThrow("Parsing is not possible");

Bu, aşağıdaki örnekte doğrulanmıştır:

expect(function () {throw new Error("Parsing is not possible")}).toThrow("Parsing is not possible");

Douglas Crockford, "yeni Hata () at ()" (prototipleme yolu) kullanmak yerine bu yaklaşımı önemle önerir:

throw {
   name: "Error",
   message: "Parsing is not possible"
}

3
Aslında toThrow koduna bakmak mutlu bir şekilde bir istisna nesnesi / veya / dize alacaktır. Örneğin beklenen.mesajına yaptığı çağrıları kontrol edin.
Pete Hodgson

1
İleti özelliği olmayan dizenin yan etkisi olarak dizeye izin vermek için dikişler
mpapis

1
İşe yarayan çok teşekkürler. Onun cevabı ben de, bende daha açık yapılan beacuse hala Pete cevabı kabul sahip bir lambda kullanmak. Hala +1 :-) Teşekkürler!
echox

16
Hata yerine bir nesne atarsanız (alttaki örnekte olduğu gibi), onu destekleyen tarayıcılarda yığın izlemesi alamazsınız.
kybernetikos

2
@kybernetikos şaşırtıcı bir şekilde, tamamen doğru değil; olmayan bir Error( jsfiddle.net/k1mxey8j ) atarsanız yine de Chrome konsolunda bir yığın izi yazdırılır . Ancak, atılan nesneniz elbette bu özelliğe sahip değildir; bu .stack, otomatik hata raporlaması ayarlamak istiyorsanız önemli olabilir .
Mark Amery

24

Tek amacı başka birini sarmak olan anonim bir işlev oluşturmaktan daha zarif bir çözüm, es5'in bindişlevini kullanmaktır . Bind işlevi, çağrıldığında, thisanahtar sözcüğü sağlanan değere ayarlanmış olan ve yeni işlev çağrıldığında sağlanan herhangi bir bağımsız değişken sırası ile yeni bir işlev oluşturur.

Onun yerine:

expect(function () { parser.parse(raw, config); } ).toThrow("Parsing is not possible");

Düşünmek:

expect(parser.parse.bind(parser, raw, config)).toThrow("Parsing is not possible");

Bağlama sözdizimi, farklı thisdeğerlere sahip işlevleri test etmenizi sağlar ve bence testi daha okunabilir hale getirir. Ayrıca bakınız: https://stackoverflow.com/a/13233194/1248889


23

Jasmine'in toThrow eşleştiricisini, istisnanın name özelliğiyle veya message özelliğiyle eşleştirmenize izin veren aşağıdakilerle değiştiriyorum. Benim için bu, aşağıdakileri yapabileceğim için testlerin yazılmasını ve daha az kırılgan olmasını sağlar:

throw {
   name: "NoActionProvided",
   message: "Please specify an 'action' property when configuring the action map."
}

ve ardından aşağıdakileri test edin:

expect (function () {
   .. do something
}).toThrow ("NoActionProvided");

Bu, önemli mesajı beklenen istisna türünü atması durumunda, istisna mesajını daha sonra testleri kırmadan değiştirmeme izin veriyor.

Bu, aşağıdakilere izin veren toThrow'un yerine geçer:

jasmine.Matchers.prototype.toThrow = function(expected) {
  var result = false;
  var exception;
  if (typeof this.actual != 'function') {
    throw new Error('Actual is not a function');
  }
  try {
    this.actual();
  } catch (e) {
    exception = e;
  }
  if (exception) {
      result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected) || this.env.equals_(exception.name, expected));
  }

  var not = this.isNot ? "not " : "";

  this.message = function() {
    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
      return ["Expected function " + not + "to throw", expected ? expected.name || expected.message || expected : " an exception", ", but it threw", exception.name || exception.message || exception].join(' ');
    } else {
      return "Expected function to throw an exception.";
    }
  };

  return result;
};

4
Hoş bir yaklaşım ama {name: '...', mesaj: '...'} JavaScript'te uygun bir Error nesnesi mi?
Marc

1
Güzel yorum @Marc. Haklısınız, name özelliği standart değil. developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/… , ama bu çok mu yanlış?
Jess

4
@Jake! Daha iyi bir yol buldum !!!! Sadece arayabilirsiniz expect(blah).toThrow(). Hiçbir argüman, atıp atmadığını kontrol etmek anlamına gelir. Dize eşleşmesi gerekmez. Ayrıca bakınız: stackoverflow.com/a/9525172/1804678
Jess

5
Teşekkürler Jess - bu doğru, ama sonra bir TypeError gibi başka bir hata atıyor olabilir ve testim yanlış bir şekilde geçecek ve gerçek bir hata maskeleyecek.
Jake

4
Artık bir RegEx'i toThrow () için bağımsız değişken olarak kullanabilirsiniz.
Tony O'Hagan

21

Daha önce de belirtildiği gibi, bir fonksiyonun toThrowtestinizde tanımladığınız fonksiyon olduğu için aktarılması gerekir : "Bu fonksiyonun x atmasını bekliyorum"

expect(() => parser.parse(raw))
  .toThrow(new Error('Parsing is not possible'));

Jasmine Eşleştiricileri kullanıyorsanız , duruma uygun olduklarında aşağıdakilerden birini de kullanabilirsiniz;

// I just want to know that an error was
// thrown and nothing more about it
expect(() => parser.parse(raw))
  .toThrowAnyError();

veya

// I just want to know that an error of 
// a given type was thrown and nothing more
expect(() => parser.parse(raw))
  .toThrowErrorOfType(TypeError);

3
Bu var expect(foo).toThrowError(TypeError);Jasmine 2,5: jasmine.github.io/2.5/introduction
Benny Neugebauer

9

Daha fazla kod olduğunu biliyorum ama sen de yapabilirsin:

try
   do something
   @fail Error("should send a Exception")
 catch e
   expect(e.name).toBe "BLA_ERROR"
   expect(e.message).toBe 'Message'

Bunun 'kendini belgeleme' yönünü
beğenme eğilimindeyim ...

6

Kahve severler için

expect( => someMethodCall(arg1, arg2)).toThrow()

3

Hala bu sorunla karşı karşıya kalan herkes için, benim için gönderilen çözüm işe yaramadı ve bu hatayı atmaya devam etti: Error: Expected function to throw an exception. Daha sonra bir hata atmayı beklediğim fonksiyonun bir asenkron işlev olduğunu ve söz vermeyi beklediğini fark ettim. reddedildi ve sonra hata atmak ve benim kodda yapıyordum:

throw new Error('REQUEST ID NOT FOUND');

ve bu benim testte yaptığım ve işe yaradı:

it('Test should throw error if request not found', willResolve(() => {
         const promise = service.getRequestStatus('request-id');
                return expectToReject(promise).then((err) => {
                    expect(err.message).toEqual('REQUEST NOT FOUND');
                });
            }));

Bunun için teşekkürler. Çok kafam karışmıştı ama yorumunuz çok mantıklı. Yeni expectAsync jasmine.github.io/api/3.3/async-matchers.html
Benjamin
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.