Ну, не соглашаясь с общим предложением Питонов о глобальном уровне модуля, как насчет этого:
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
Проще всего было бы использовать встроенную поддержку обещаний, которую 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
), но лично я предпочитаю ясность и простоту текущей версии
Как уже указывалось здесь , более новые версии Mocha уже осведомлены о Promise. Но поскольку ОП задал конкретно вопрос о Чай, справедливо отметить пакет chai-as-promised
, который обеспечивает чистый синтаксис для тестирования обещаний:
как вы можете использовать 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-обещал:
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'); })
;
});
catch
вызывается, когда один из expect(s)
терпит неудачу. Это дает неправильное представление о том, что обещание потерпело неудачу, даже если этого не произошло. Это только ожидаемый результат.
– TheCrazyProgrammer
8 June 2017 в 00:48
Chai.use
, чтобы установить его. Я бы никогда не выбрал это из документации, которую они имели. | :(
– Arcym
29 June 2017 в 03:50
async/await
Функция с задержкой обещания, которая терпит неудачу, если задана задержка 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. Если вы не хотите тестировать что-либо еще, используйте другой блок () -.
Ensure the done() callback is being called in this test
при попытке сделать это с помощью mocha 2.2.5. – Scott 19 June 2015 в 19:16done
вit
, который отказался бы от него. – Benjamin Gruenbaum 19 June 2015 в 19:16done
в моем обратном вызовеit
и явное обращение кreturn
(по обещанию) в обратном вызове - это то, как я получил его работу, как в фрагменте кода. – JohnnyCoder 8 December 2015 в 16:40Alternately, 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:10done
для вызоваit
, и это все еще происходит ... – Alhadis 9 July 2016 в 16:56