Chai: ожидание ошибки или отсутствие зависимости от параметра

Я пытался сделать текст функции, которая обрабатывает ошибки таким образом, что, если это действительная ошибка, она выдается, но если это не так, то ничего не выбрасывается. Проблема в том, что я не могу установить параметр при использовании:

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

Идеальным было бы использование:

expect(handleError(validError)).to.throw(Error);

Есть ли способ реализовать эту функциональность?

код функции:

function handleError (err) {
    if (err !== true) {
        switch (err) {
            case xxx:
            ...
        }
        throw "stop js execution";
    else {}
}

И код теста (не работает по назначению):

it("should stop Javascript execution if the parameter isnt \"true\"", function() {
    expect(handleError).to.be.a("function");
    expect(handleError(true)).to.not.throw(Error);
    expect(handleError("anything else")).to.throw(Error);
});

person Apzx    schedule 30.09.2013    source источник


Ответы (4)


Проблема в том, что вы вызываете handleError, а затем передаете ожидаемый результат. Если handleError бросает вызов, то expect никогда даже не вызывается.

Вам нужно отложить вызов handleError до тех пор, пока не будет вызвана функция expect, чтобы ожидание могло видеть, что происходит при вызове функции. К счастью, это то, что ожидает ожидание:

expect(function () { handleError(true); }).to.not.throw();
expect(function () { handleError("anything else") }).to.throw("stop js execution");

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

person David Norman    schedule 03.10.2013
comment
как этого можно достичь с помощью «должен»? - person matus; 11.07.2014
comment
хорошо, понял should.Throw(function(){handleError("anything else");}, Error); - person matus; 11.07.2014
comment
Не вводите 'handleError().should.throw()'. Это просто '(function(){handlerError();}).should.throw()'. Я этого не знал... Это отбрасывает много времени в мусор. - person NHK; 30.08.2014
comment
Я пошел с expect(() => throwAnError(true)).to.throw(); - person Silviu-Marian; 20.11.2016
comment
Это имеет больше смысла, чем вопрос о том, что это было отмечено как дубликат - person ; 15.07.2017

Сегодня я столкнулся с той же проблемой и выбрал другое решение, не упомянутое здесь: приложение частичной функции с использованием bind():

expect(handleError.bind(null, true)).to.not.throw();
expect(handleError.bind(null, "anything else")).to.throw("stop js execution");

Преимущество этого заключается в том, что он краток, использует старый добрый JavaScript, не требует дополнительных функций, и вы даже можете указать значение this, если ваша функция зависит от него.

person Sven Schoenung    schedule 24.04.2016
comment
не требующие дополнительных функций - это неправда. Под капотом метод привязки создает HOF (функция высокого порядка). Тем не менее, это то же самое решение, что и упомянутое выше, за исключением возможности более явно передавать контекст. - person Skay; 29.08.2016
comment
@Skay никаких дополнительных функций просто означает, что вам не нужно писать вспомогательную функцию, как предлагается в этом ответе. bind() сам создает и возвращает новую функцию, конечно. - person Sven Schoenung; 29.08.2016

Оборачивать вызов функции в лямбда-выражение, как рекомендовал Дэвид Норман, безусловно, является одним из хороших способов решения этой проблемы.

Однако вы можете добавить это в свои утилиты для тестирования, если ищете более удобочитаемое решение. Эта функция заключает вашу функцию в объект с помощью метода withArgs, что позволяет вам написать тот же оператор в более читаемом виде. В идеале это должно быть встроено в Chai.

var calling = function(func) {
  return {
    withArgs: function(/* arg1, arg2, ... */) {
      var args = Array.prototype.slice.call(arguments);
      return function() {
        func.apply(null, args);
      };
    }
  };
};

Затем используйте его как:

expect(calling(handleError).withArgs(true)).to.not.throw();        
expect(calling(handleError).withArgs("anything else")).to.throw("stop js execution");

Читается как английский!

person morsecoder    schedule 04.01.2016
comment
Какие преимущества дает ваше решение по сравнению со встроенной функцией привязки? - person Skay; 29.08.2016
comment
@Скай удобочитаемость. Он выполняет то же самое. - person morsecoder; 29.08.2016

Я использую ES2015 с пресетом babel stage-2, и если вы это сделаете, вы также можете использовать его.

Я взял решение @StephenM347 и немного изменил его, чтобы сделать его короче и еще более читаемым ИМХО:

let expectCalling = func => ({ withArgs: (...args) => expect(() => func(...args)) });

Использование :

expectCalling(handleError).withArgs(true).to.not.throw();        
expectCalling(handleError).withArgs("anything else").to.throw("stop js execution");

Примечание: если вы хотите использовать то же самое (и придерживаться expect() как есть):

    let calling = func => ({ withArgs: (...args) => () => func(...args) });
person Pandaiolo    schedule 24.01.2016