【问题标题】:Mocha test cases executes before promise gets the dataMocha 测试用例在 Promise 获取数据之前执行
【发布时间】:2018-11-30 17:47:26
【问题描述】:

测试用例(Test1, Test2) 在promise 获取数据之前执行。这是文件 mockExecution.js

describe('AC 1: This is suite one', ()=>
{
    before((done)=>
    {
        promiseResp.then((data) => {
            console.log("i am in the promise");
            responseData = data;
            process.exit(0);
        }, (err) => {
            console.log('promiseResp.err', err);
            process.exit(1);
        })
        done();
    })
    it('Test1', (done)=>
    {
        expect(responseData.measure.abc).not.toBe(responseData.measure_list.abc);
        done();
    });

    it('Test2', (done)=>
    {

        expect(responseData.measure.abc).not.toBe(responseData.measure_list.abc);
        done();
    });

});

Before 块内的 PromiseResp 不执行。因此“responseData”变量没有数据,它会抛出测试用例失败。我想有一些异步时间问题,但不知道如何解决它,也不知道我把这个“process.exit(0)”放在哪里。下面是实际输出:

AC 1: This is suite one
I am in the before
    1) Test1
    2) Test2


  0 passing (7ms)
  2 failing

  1) AC 1: This is suite one
       Test1:
     TypeError: Cannot read property 'measure' of undefined
      at Context.it (QA/mockExecution.js:160:29)

  2) AC 1: This is suite one
       Test2:
     TypeError: Cannot read property 'measure' of undefined
      at Context.it (QA/mockExecution.js:167:29)

[process business logic and prints some logs here, i can't paste here]
finished analyzing all records
i am in the promise
npm ERR! Test failed.  See above for more details.

我希望按以下顺序输出:

[process business logic and prints some logs here, I can't paste here]
finished analyzing all records
AC 1: This is suite one
    I am in the before
       I am in the promise
        1) Test1 passed
        2) Test2 paseed

【问题讨论】:

  • 你之前为什么要做process.exit?一旦你的承诺真正解决,你就会退出整个测试套件。在这种情况下,这并不重要,因为您错误地运行it 测试之前 Promise 实际解决。

标签: node.js mocha.js


【解决方案1】:

你需要打电话给done你的then&之后你实际上 分配responseData = data:

before((done) => {
  promiseResp.then((data) => {
    responseData = data;
    // Promise has resolved. Calling `done` to proceed to the `it` tests.
    done();
  })
  .catch((err) => {
    // Calling `done` with a truthy `err` argument, in case
    // the promise fails/rejects, to fail-early the test suite.
    done(err);
  })
})

否则before 会提前结束并继续进行下一个测试,然后才会真正解决并分配您的responseData 变量。

这是一个使用 before 钩子的工作示例:

const expect = require('chai').expect

const getFooValue = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('foo')
    }, 500)
  })
}

describe('#getFooValue()', function () {
  let responseData

  before(done => {
    getFooValue().then(data => {
      responseData = data
      done()
    })
    .catch(err => {
      done(err)
    })
  })

  it('response has a value of foo', () => {
    expect(responseData).to.equal('foo');
  })

  it('response is a String', () => {
    expect(responseData).to.be.a('String');
  })
})

你现在做的是:

  • 您定义Promise
  • 您(过早地)调用done,Mocha 继续执行it 测试。
  • it 测试在 responseData 仍为 undefined 时运行。
  • before 中的Promise 最终会解析并分配responseData 变量。

...但到那时为时已晚。测试已经运行。

【讨论】:

  • 我还必须明确 --timeout "test":"mocha **/mockExecution.js --timeout 4000"
  • @pk786 可能是因为您的Promise 解析速度比 Mocha 的默认 2000 毫秒超时慢。另外仅供参考,尽管我的回答指出了您的代码的问题并且工作正常,但上面的 estus 回答比我的更正确。
【解决方案2】:

done 与 Promise 一起使用是一种反模式,因为这通常会导致不正确的控制流,就像在这种情况下一样。所有主要的测试框架都已经支持 Promise,包括 Mocha。

如果默认超时(2 秒)不足以解决 promise,则应增加超时值,例如如this answer 中所述,通过将其设置为当前测试套件(thisdescribe 上下文中)。请注意,箭头函数应替换为常规函数以到达套件上下文。

应该是:

describe('AC 1: This is suite one', function () {
    this.timeout(60000);

    before(() => {
        return promiseResp.then((data) => {
            responseData = data;
        });
    });

    it('Test1', () => {            
       expect(responseData.measure.abc).not.toBe(responseData.measure_list.abc);
    });
    ...

承诺不需要catch;承诺拒绝将由框架处理。测试中不需要done;它们是同步的。

【讨论】:

  • 该死的,这正是我在测试中所做的,但是我继续前进并以不太理想的解决方案回答。去搞清楚。 +1。
  • 给我错误:1)“之前”钩子 0 通过(2 秒)1 失败 1)“之前”钩子:错误:超过 2000 毫秒的超时。对于异步测试和钩子,确保调用了“done()”;如果返回 Promise,请确保它已解决。
  • @pk786 正如您已经在另一条评论中指出的那样,问题是超时不够大。为了清楚起见,我更新了答案。
  • @estus 您在哪里看到缺少的catch?你能评论我的回答吗?
  • @NicholasKyriakides 抱歉,我将您的答案与页面重新加载时出现在同一位置的另一个答案混淆了。 catch 在你那里没问题。赞成它,它清楚地解释了为什么done 不能按预期工作。
【解决方案3】:

你的 it() 中没有承诺,所以没有理由做 done(),但它应该在 then() 中调用,因为它是一个回调。

总的来说,使用 async/await 更简洁。但是在 before() 中它并不能很好地工作。

另外,'function()' 最好在 describe() 中设置测试超时(根据我的经验,将其作为链式方法调用从未起作用)

describe('AC 1: This is suite one', function() {
  this.timeout(12000); //12 sec timeout for each it()
  before((done) => {
     promiseResp().then((data) => {
         responseData = data;
         done();
     })      
  })

  it('Test1', () => {
      expect(responseData.measure.abc).not.toBe(responseData.measure_list.abc);
  });

  it('Test2', () => {
      expect(responseData.measure.abc).not.toBe(responseData.measure_list.abc);
  });

});

【讨论】:

  • 我在 package.json 文件中添加了注释,例如:test":"mocha **/mockExecution.js --timeout 4000"
  • @pk786 我想知道将它作为命令参数传递是单独设置 it() 的超时时间,还是设置整个文件运行的超时时间?你能澄清一下吗?
  • @DanielSerendipity 将超时作为命令行参数设置该文件中所有测试的超时。
猜你喜欢
  • 2021-04-24
  • 1970-01-01
  • 2017-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-17
  • 2021-11-15
  • 1970-01-01
相关资源
最近更新 更多