【问题标题】:chai-as-promised rejection doesn't fail test but only print warning insteadchai-as-promised 拒绝不会失败测试,​​而只会打印警告
【发布时间】:2022-02-10 22:59:27
【问题描述】:

我正在使用chai-as-promised 来测试我的readIndex(path): string 功能。

readIndex() 返回一个 promise,然后尝试打开目标文件夹中名为 index.json 的文件并将其解析为 JSON。

请参阅以下摘录:

// readIndex.js
module.exports = path =>
  new Promise((resolve, reject) => {
    try {
      const buffer = fs.readFileSync(path + '/index.json')
      const data = JSON.parse(buffer.toString())
      resolve(data)
    } catch (err) {
      if (err.code === 'ENOENT') {
        reject(Error('file not found'))
      } else if (err instanceof SyntaxError) {
        reject(Error('format not json'))
      } else {
        reject(err)
      }
    }
  })

在我的案例测试的模拟中,返回的承诺拒绝并出现错误“找不到文件”。

但实际上我正在测试一个(应该是)有效的案例,只有在承诺成功解决的情况下才应该通过 ...

至少这是我对promise.should.be.fulfilled 用法的理解。

查看相关测试:

// readIndex.test.js
chai.use(chaiAsPromised)
chai.should()

describe('SUCCESS :', () => 
  it('should resolve with a (markdown) string extrapoled from target folder index file', done => {
    const key = 'content success'
    mock(_mocks[key])
    const promise = readIndex('test')
    promise.should.be.fulfilled
    mock.restore()
    done()
  }))

通过这样的设置,运行测试不会使其失败;它会打印此消息:

    SUCCESS :
          √ should resolve with a (markdown) string extrapoled from target folder index file
    (node:183516) UnhandledPromiseRejectionWarning: AssertionError: expected promise to be fulfilled but it was rejected with 'Error: file not found'
    (node:183516) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 10)
    (node:183516) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

当然,预期的结果应该是失败的测试运行,在控制台中是这样的:

SUCCESS :
         1) should resolve with a (markdown) string extrapoled from target folder index file:

      AssertionError: expected '1' to equal '2'

这种奇怪的行为甚至会导致(有趣和)不连贯的警告。

使用promise.should.not.be.rejected,我得到“预期不会被拒绝但被拒绝的承诺”但测试仍然通过:

SUCCESS :
      √ should resolve with a (markdown) string extrapoled from target folder index file
(node:225676) UnhandledPromiseRejectionWarning: AssertionError: expected promise not to be rejected but it was rejected with 'Error: file not found'

其实我的想法是:

  • 一种解决方案是将测试失败的级别提高到警告,但我在chai-as-promised 文档中没有找到它。

  • 另一种解决方案是了解哪个层正在捕获错误/拒绝,并将其降低为警告。也许是chai-as-promised 默认参数?

【问题讨论】:

  • 假设你需要一个 Promise,在某些情况下你的 Promise 既不会解决也不会拒绝。 if (err.code === 'ENOENT') {...} 需要else {reject(err)}。
  • 是的,你是对的。它在我的代码中,但我只是缩短了要发布的代码,抱歉
  • 你会注意到我还在输入这个if (err.code === 'ENOENT'),因为第一行的警告证明了这一点
  • 只是想我会提到它,以防不履行承诺可能是一个促成因素。

标签: javascript node.js promise chai


【解决方案1】:

我刚刚在chai-as-promised documentation 中发现了这个小事实:

测试“行”(我没有更好的词)前面必须有一个 return 声明。 p>

让我们看一下他们的第一个示例:

return doSomethingAsync().should.eventually.equal("foo")

下面的也很有意思:

或者如果您遇到不宜退货的情况(例如样式 考虑)或不可能(例如,测试框架没有 允许返回 promise 来表示异步测试完成),然后 您可以使用以下解决方法(其中 done() 由 测试框架):

doSomethingAsync().should.eventually.equal("foo").notify(done);

它对我有用。

希望对大家有所帮助。

【讨论】:

  • 你在mock.restore()声明中的表现如何?
  • 我对这个主题不太满意,但我认为 promise 有点像打开一个并行线程,不会中断主线程。 Promise 被实例化,并且测试指令不断被执行。我想一个更好的选择是在mock() 消耗测试结束时执行mock.restore()。你怎么看?
  • 事实是,模拟被测试正确读取(输出与预期一样,我将它白盒以检查fs.readdir()结果)并且我之前没有检查正确的恢复值执行另一个测试
  • await 而不是 return 也应该可以解决问题(或者甚至可能工作得更好)
【解决方案2】:

我最初使用的是chai-as-promised,但由于没有正确等待承诺,导致我的测试需要数小时的调试时间。

最后我推出了自己的解决方案。

EDIT v2 - 更简洁

// test-utils.ts

import { expect } from "chai";

export const expectRejection = async (
  promise: Promise<any>,
  errMsg: string
): Promise<void> => {
  try {
    await promise;
  } catch (err) {
    expect(err.message).eq(errMsg);
    return;
  }
  throw Error('Promise was not rejected');
};

你可以在你的测试中使用这样的函数

it('Function that fails', async () => {
  const errMsg = 'My example';
  const functionThatRejects = async () => {
    throw Error(errMsg);
  };
  await expectRejection(functionThatRejects(), errMsg);
});

为了完整起见,这里是函数的单元测试。

import { expectRejection } from './test-utils';
import { expect } from 'chai';

describe('test-utils.ts', () => {
  describe('expectRejection(..)', () => {
    it('Function that fails', async () => {
      const errMsg = 'My example';
      const functionThatRejects = async () => {
        throw Error(errMsg);
      };
      await expectRejection(functionThatRejects(), errMsg);
    });

    it("Function that doesn't fail", async () => {
      const functionThatResolves = async () => null;
      try {
        await expectRejection(functionThatResolves(), "Random error message");
      } catch (err) {
        expect(err).match(/Promise was not rejected/);
        return;
      }
      throw Error('Should have already returned');
    });
  });
});

v1 - 更灵活

// test-utils.ts

import { expect } from "chai";

export const expectRejection = async (promise: Promise<any>) => {
  try {
    await promise;
  } catch (err) {
    return expect(err);
  }
  throw Error('Promise was not rejected');
};

你可以在你的测试中使用这样的函数

it('Function that fails', async () => {
  const functionThatRejects = async () => {
    throw Error('My example');
  };
  const rejection = await expectRejection(functionThatRejects());
  rejection.match(/My example/);
});

为了完整起见,这里是函数的单元测试。

// test-utils.spec.ts

import { expectRejection } from './test-utils';
import { expect } from 'chai';

describe('expectRejection(..)', () => {
  it('Function that fails', async () => {
    const functionThatRejects = async () => {
      throw Error('My example');
    };
    const rejection = await expectRejection(functionThatRejects());
    rejection.match(/My example/);
  });

  it("Function that doesn't fail", async () => {
    const functionThatResolves = async () => null;
    try {
      await expectRejection(functionThatResolves());
    } catch (err) {
      expect(err).match(/Promise was not rejected/);
      return;
    }
    throw Error('Should have already returned');
  });
});


【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-22
    • 2021-07-24
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 2015-06-02
    • 2018-06-01
    • 1970-01-01
    相关资源
    最近更新 更多