Подтвердить что ты не робот

Тест на ожидаемый сбой в Mocha

Используя Mocha, я пытаюсь проверить, вызывает ли конструктор ошибку. Я не смог сделать это, используя синтаксис ожидания, поэтому я хотел бы сделать следующее:

it('should throw exception when instantiated', function() {
  try {
    new ErrorThrowingObject();
    // Force the test to fail since error wasn't thrown
  }
  catch (error) {
   // Constructor threw Error, so test succeeded.
  }
}

Возможно ли это?

4b9b3361

Ответ 1

Вы можете попробовать использовать конструкцию Chai throw. Например:

expect(Constructor).to.throw(Error);

Ответ 2

should.js

Использование библиотеки should.js с should.fail

var should = require('should')
it('should fail', function(done) {
  try {
      new ErrorThrowingObject();
      // Force the test to fail since error wasn't thrown
       should.fail('no error was thrown when it should have been')
  }
  catch (error) {
   // Constructor threw Error, so test succeeded.
   done();
  }
});

Альтернативу вы можете использовать throwError

(function(){
  throw new Error('failed to baz');
}).should.throwError(/^fail.*/)

Chai

И с помощью chai, используя throw api

var expect = require('chai').expect
it('should fail', function(done) {
  function throwsWithNoArgs() {
     var args {} // optional arguments here
     new ErrorThrowingObject(args)
  }
  expect(throwsWithNoArgs).to.throw
  done()
});

Ответ 4

Ответ 2017, если вам нужно сделать это с помощью асинхронного кода: использовать await и не требовать никаких других библиотек.

it('Returns a correct error response when making a broken order', async function(){
  this.timeout(5 * 1000);
  var badOrder = {}
  try {
    var result = await foo.newOrder(badOrder)
    // The line will only be hit if no error is thrown above!
    throw new Error('Expected an error and didn't get one!')
  } catch(err) {
    var expected = 'Missing required field'
    assert.equal(err.message, expected)
  }
});

Заметьте, что постер делал только код синхронизации, но я ожидаю, что многие люди, использующие асинхронный режим, приводят здесь заголовок вопроса!

Ответ 5

Mocha по умолчанию использует Assert из node.js(https://nodejs.org/api/assert.html). Вам не нужны внешние библиотеки, чтобы проверить, вызывает ли метод ошибку.

У Assert есть метод - assert.throws, он имеет три параметра, но здесь только два:

  • функция - здесь функция передачи, не вызов функции
  • error - здесь передается или объект-конструктор или функция для проверки ошибки

Предположим, что у вас есть функция с именем sendMessage(message), которая выдает ошибку, когда параметр сообщения не задан. Код функции:

function sendMessage(message) {
  if (!message || typeof message !== 'string') {
     throw new Error('Wrong message');
  }
  // rest of function
}

Хорошо, поэтому для его проверки вам нужна дополнительная функция для ввода ввода. Зачем? Поскольку assert.throws не дает возможности передавать параметры функции, которая будет протестирована.

Итак, вместо

// WRONG
assert.throws(sendMessage, Error); // THIS IS WRONG! NO POSSIBILITY TO PASS ANYTHING

вам нужно создать анонимную функцию:

// CORRECT
assert.throws(() => {
  sendMessage(12);  // usage of wanted function with test parameters
}, Error)

Вы видите разницу? Вместо прямой передачи функции я поместил вызов функции внутри анонимной функции, чтобы вызвать ее с подготовленным вводом.

Как насчет второго параметра. Это зависит от того, какую ошибку следует выбросить, в приведенном выше примере Error объект был брошен, поэтому мне пришлось поставить там Error. В результате этого действия assert.throws сравнивается, если брошенный объект является объектом того же типа. Если вместо Error будет выбрано что-то другое, тогда эту часть нужно изменить. Например, вместо Error я вывожу значение типа String.

function sendMessage(message) {
  if (!message || typeof message !== 'string') {
     throw 'Wrong message'; // change to String
  }
  // rest of function
}

Теперь тестовый вызов

assert.throws(() => {
  sendMessage(12); // usage of wanted function with test parameters
}, (err) => err === 'Wrong message')

Вместо Error во втором параметре я использовал функцию сравнения, чтобы сравнить полученную ошибку с ожиданием.

Ответ 6

Если вы используете should.js, вы можете сделать (new ErrorThrowingObject).should.throw('Option Error Text or Regular Expression here')

Если вы не хотите иметь отдельную библиотеку, вы также можете сделать что-то вроде этого:

it('should do whatever', function(done) {
    try {
        ...
    } catch(error) {
        done();
    }
}

Таким образом, вы знаете, что ошибка улавливается, если тест завершается. В противном случае вы получите ошибку тайм-аута.

Ответ 7

Принятый MarkJ ответ - это путь, который намного проще, чем другие. Позвольте мне показать пример из реальной жизни:

function fn(arg) {
  if (typeof arg !== 'string')
    throw TypeError('Must be an string')

  return { arg: arg }
}

describe('#fn', function () {
  it('empty arg throw error', function () {
    expect(function () {
      new fn()
    }).to.throw(TypeError)
  })

  it('non-string arg throw error', function () {
    expect(function () {
      new fn(2)
    }).to.throw(TypeError)
  })

  it('string arg return instance { arg: <arg> }', function () {
    expect(new fn('str').arg).to.be.equal('str')
  })
})

Ответ 8

С Chai throw (ES2016)

http://chaijs.com/api/bdd/#method_throw

Для ясности... Это работает

it('Should fail if ...', done => {
    let ret = () => {
        MyModule.myFunction(myArg);
    };
    expect(ret).to.throw();
    done();
});

Это не работает

it('Should fail if ...', done => {
    let ret = MyModule.myFunction(myArg);
    expect(ret).to.throw();
    done();
});

Ответ 9

Если вы не хотите, чтобы обернуть всю массу источника в expect параметра, или если у вас есть много аргументов, чтобы пройти, и он просто становится уродливым, вы можете сделать это с помощью оригинального синтаксиса просто отлично за счет использования done аргумент, при условии (но изначально был проигнорирован):

it('should throw exception when instantiated', function(done: Done) {
  try {
    new ErrorThrowingObject();
    done(new Error('Force the test to fail since error wasn't thrown'));
  }
  catch (error) {
    // Constructor threw Error, so test succeeded.
    done();
  }
}

Поскольку вы используете здесь done, он позволяет вам выполнить произвольный код над ним при try, а затем точно указать, где в вашем источнике вы хотите записать ошибку.

Как правило, кто - то может возникнуть соблазн throw или assert(false), но они оба будут пойманы catch в try, и заставить вас сделать некоторые мета-проверки, чтобы определить, является ли ошибка, которую вы поймали была ожидаемая ошибка из теста или, если это было окончательное решение, что ваш тест не прошел. Это просто беспорядок.