Ошибка теста из функции async с использованием async / await [duplicate]

Ну, не соглашаясь с общим предложением Питонов о глобальном уровне модуля, как насчет этого:

def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class2, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w, class2).__new__(class2, *args, **kwargs)
                class_w._instance._sealed = False
            return class_w._instance
        def __init__(self, *args, **kwargs):
            if self._sealed:
                return
            super(class_w, self).__init__(*args, **kwargs)
            self._sealed = True
    class_w.__name__ = class_.__name__
    return class_w

@singleton
class MyClass(object):
    def __init__(self, text):
        print text
    @classmethod
    def name(class_):
        print class_.__name__

x = MyClass(111)
x.name()
y = MyClass(222)
print id(x) == id(y)

Выход:

111     # the __init__ is called only on the 1st time
MyClass # the __name__ is preserved
True    # this is actually the same instance
113
задан Zoltan Kochan 9 January 2016 в 18:39
поделиться

3 ответа

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

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

Или с современным узлом и асинхронным / ждущим:

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

. Поскольку этот подход обещает до конца, его легче тестировать, и вам не придется думать о странных случаях, о которых вы думаете, как о нечетных вызовах done() во всем мире.

Это преимущество, которое Моча имеет в отношении других библиотек, таких как Jasmine на данный момент. Вы также можете проверить Chai As Promised , что сделало бы его еще проще (нет .then), но лично я предпочитаю ясность и простоту текущей версии

186
ответ дан Benjamin Gruenbaum 20 August 2018 в 15:17
поделиться
  • 1
    В какой версии Mocha это началось? Я получаю ошибку Ensure the done() callback is being called in this test при попытке сделать это с помощью mocha 2.2.5. – Scott 19 June 2015 в 19:16
  • 2
    @Scott не принимает параметр done в it, который отказался бы от него. – Benjamin Gruenbaum 19 June 2015 в 19:16
  • 3
    Это было очень полезно для меня. Удаление done в моем обратном вызове it и явное обращение к return (по обещанию) в обратном вызове - это то, как я получил его работу, как в фрагменте кода. – JohnnyCoder 8 December 2015 в 16:40
  • 4
    Удивительный ответ, прекрасно работает. Оглядываясь на документы, он там - просто пропустить, я думаю. 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 10 January 2016 в 21:10
  • 5
    Имеет ту же проблему, что и Скотт. Я не передаю параметр done для вызова it, и это все еще происходит ... – Alhadis 9 July 2016 в 16:56

Как уже указывалось здесь , более новые версии Mocha уже осведомлены о Promise. Но поскольку ОП задал конкретно вопрос о Чай, справедливо отметить пакет chai-as-promised, который обеспечивает чистый синтаксис для тестирования обещаний:

с использованием chai-as-обещанного

как вы можете использовать chai-as-обещали протестировать оба случая resolve и reject для обещания:

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

без chai-as-обещанного

Чтобы сделать это действительно ясно, что тестируется, вот тот же пример, закодированный без chai-as-обещал:

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'); })
            ;
});
25
ответ дан Community 20 August 2018 в 15:17
поделиться
  • 1
    Проблема со вторым подходом заключается в том, что catch вызывается, когда один из expect(s) терпит неудачу. Это дает неправильное представление о том, что обещание потерпело неудачу, даже если этого не произошло. Это только ожидаемый результат. – TheCrazyProgrammer 8 June 2017 в 00:48
  • 2
    Привет, спасибо, что сказал мне, что я должен позвонить Chai.use, чтобы установить его. Я бы никогда не выбрал это из документации, которую они имели. | :( – Arcym 29 June 2017 в 03:50

Вот мой прием:

  • с использованием async/await
  • , не нуждающихся в дополнительных модулях chai
  • , избегая проблемы с catch, @TheCrazyProgrammer указал выше

Функция с задержкой обещания, которая терпит неудачу, если задана задержка 0:

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')
})

Положительный тест довольно прост. Неожиданный сбой (имитация с помощью 500→0) автоматически завершит тест, так как отклоненное обещание возрастает.

Отрицательный тест использует идею try-catch. Однако: «жалобы» на нежелательный проход происходит только после предложения catch (таким образом, это не заканчивается в предложении catch (), вызывая дальнейшие, но вводящие в заблуждение ошибки.

Чтобы эта стратегия работала, нужно вернуть тест из предложения catch. Если вы не хотите тестировать что-либо еще, используйте другой блок () -.

1
ответ дан Frank Nocke 20 August 2018 в 15:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: