[node.js] 모카와 차이로 약속을 올바르게 테스트하려면 어떻게해야합니까?

다음 테스트는 이상하게 작동합니다.

it('Should return the exchange rates for btc_ltc', function(done) {
    var pair = 'btc_ltc';

    shapeshift.getRate(pair)
        .then(function(data){
            expect(data.pair).to.equal(pair);
            expect(data.rate).to.have.length(400);
            done();
        })
        .catch(function(err){
            //this should really be `.catch` for a failed request, but
            //instead it looks like chai is picking this up when a test fails
            done(err);
        })
});

거부 된 약속을 올바르게 처리하고 테스트하려면 어떻게해야합니까?

실패한 테스트를 어떻게 올바르게 처리해야합니까 (예 : expect(data.rate).to.have.length(400);?

테스트하고있는 구현은 다음과 같습니다.

var requestp = require('request-promise');
var shapeshift = module.exports = {};
var url = 'http://shapeshift.io';

shapeshift.getRate = function(pair){
    return requestp({
        url: url + '/rate/' + pair,
        json: true
    });
};



답변

가장 쉬운 방법은 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
});

또는 현대 노드와 async / await :

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()어디에서나 이상한 전화 처럼 생각하는 이상한 경우에 대해 생각할 필요가 없습니다 .

이것은 현재 Mocha가 Jasmine과 같은 다른 라이브러리보다 장점입니다. 당신은 또한 확인 할 수 있습니다 차이로이 약속 이 더 쉽게 (더하지 않습니다 것이다 .then)하지만 개인적으로는 현재 버전의 명확성과 단순성을 선호


답변

이미 지적한 바와 같이 여기 , 모카의 최신 버전은 이미 약속-알고 있습니다. 그러나 OP가 Chai에 대해 구체적으로 물었으므로 chai-as-promised약속을 테스트하기위한 깔끔한 구문을 제공하는 패키지 를 지적하는 것이 공평합니다 .

약속 된 차이를 사용하여

약속의 약속을 사용 하여 약속에 대한 사례 resolvereject사례를 모두 테스트하는 방법은 다음과 같습니다 .

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

약속 된 차이없이

테스트 대상에 대해 명확히하기 위해 다음은 약속의 여지없이 코딩 된 동일한 예제입니다.

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


답변

여기 내 테이크가있다 :

  • 사용 async/await
  • 추가 차이 모듈이 필요하지 않음
  • 캐치 문제를 피하면서 @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거부 된 약속이 에스컬레이션되면 예기치 않은 실패 (by by simulate )가 테스트에 자동으로 실패합니다.

부정적인 테스트 는 try-catch-idea를 사용합니다. 그러나 원치 않는 패스에 대한 ‘신고’는 catch 절 이후에만 발생합니다 (그러면 catch () 절에서 끝나지 않아 잘못된 오류를 유발합니다.

이 전략이 작동하려면 catch 절에서 테스트를 반환해야합니다. 다른 것을 테스트하지 않으려면 다른 it ()-block을 사용하십시오.


답변

더 나은 솔루션입니다. catch 블록에서 done으로 오류를 반환하십시오.

// ...

it('fail', (done) => {
  // any async call that will return a Promise 
  ajaxJson({})
  .then((req) => {
    expect(1).to.equal(11); //this will throw a error
    done(); //this will resove the test if there is no error
  }).catch((e) => {
    done(e); //this will catch the thrown error
  });
});

이 테스트는 다음 메시지와 함께 실패합니다. AssertionError: expected 1 to equal 11


답변