Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何使用Mocha+Chai编写测试,以期望setTimeout出现异常?_Javascript_Typescript_Mocha.js_Chai - Fatal编程技术网

Javascript 如何使用Mocha+Chai编写测试,以期望setTimeout出现异常?

Javascript 如何使用Mocha+Chai编写测试,以期望setTimeout出现异常?,javascript,typescript,mocha.js,chai,Javascript,Typescript,Mocha.js,Chai,我有以下建议: it('invalid use', () => { Matcher(1).case(1, () => {}); }); case方法应该在一些延迟之后抛出,我如何描述它为Mocha/Chai?这就是我想要的-测试应该通过,并且在没有抛出异常时不能通过 将案例方法视为禁区,它不能更改 出于测试目的,其应等同于: it('setTimeout throw', _ => { setTimeout(() => { throw new Error(); }

我有以下建议:

it('invalid use', () => {
  Matcher(1).case(1, () => {});
});
case方法应该在一些延迟之后抛出,我如何描述它为Mocha/Chai?这就是我想要的-测试应该通过,并且在没有抛出异常时不能通过

将案例方法视为禁区,它不能更改

出于测试目的,其应等同于:

it('setTimeout throw', _ => {
  setTimeout(() => { throw new Error(); }, 1); // this is given, cannot be modified
});
我试过:

it('invalid use', done => {
  Matcher(1).case(1, () => {});
  // calls done callback after 'case' may throw
  setTimeout(() => done(), MatcherConfig.execCheckTimeout + 10);
});
但这并没有真正帮助我,因为测试行为是完全恢复的——当case setTimeout中的异常没有被抛出时,它应该失败,当异常被抛出时,测试应该成功

我在某个地方读到有人提到全局错误处理程序,但我想用摩卡和/或柴干净地解决这个问题,如果可能的话,我想摩卡已经在以某种方式使用它了。

来自:

当没有提供参数时,.throw调用目标函数并断言抛出了错误

所以你可以说

expect(Matcher(1).case(1, () => {})).to.throw

您不能在异步回调中处理异常,例如,请参阅。这与ECMAScript使用的执行模型有关。我认为捕获它的唯一方法实际上是采用一些特定于环境的全局错误处理,例如process.on'uncaughtException'。。。在Node.js中

但是,如果您将函数转换为承诺,则可以使用Chai插件轻松测试它:

任何类似于之前、之后或之后的Mocha语句都将异步工作,如果您返回承诺。对于异步测试,我通常使用如下内容。 也别忘了设置这个超时。超时。。。如果您希望异步函数花费2秒以上的时间

it('some test', () => {
    return new Promise(function(resolve,reject){
        SomeAsyncFunction(function(error,vals) {
            if(error) {
                 return reject(error);    
            } else {
                try {
                    //do some chai tests here
                } catch(e) {
                    return reject(e);
                }
                return resolve();
            }
        });
    });
});
特别是对于您的案例,由于我们预计在一段时间后会抛出一些错误(假设您提供给的回调为空)。由于抛出异常,案例不应运行,因此您可以编写如下代码:

it('invalid use', () => {
    //define the promise to run the async function
    let prom = new Promise(function(resolve,reject){
        //reject the promise if the function does not throw an error
        //note I am assuming that the callback won't run if the error is thrown
        //also note this error will be passed to prom.catch so need to do some test to make sure it's not the error you are looking for.
        Matcher(1).case(1, () => {return reject(new Error('did not throw'))});
    });
    prom.catch(function(err){
        try {
            expect(err).to.be.an('error');
            expect(err.message).to.not.equal('did not throw');
            //more checks to see if err is the error you are looking for
        } catch(e) {
            //err was not the error you were looking for
            return Promise.reject(e);
        }
        //tests passed
        return Promise.resolve();
    });
    //since it() receives a promise as a return value it will pass or fail the test based on the promise.
    return prom;
});
如果您的测试代码使用抛出的回调调用setTimeout,但没有人捕捉到该异常,则:

1此代码已被破坏

2查看该问题的唯一方法是类似于平台全局异常处理程序的流程

最后一种方法是在测试期间使用存根setTimeout,例如使用sinon.stub或仅手动

在这种存根setTimeout中,您可以修饰超时处理程序,检测异常并调用适当的断言


请注意,这是最后的解决方案-您的应用程序代码已损坏,应予以修复以正确传播错误,不仅用于测试,而且。。。好吧,做个好代码

伪代码示例:

它“测试”,完成=>{ const originalSetTimeout=setTimeout; setTimeout=回调,超时=>{ originalSetTimeout=>{ 试一试{ 回调; }捕捉错误{ //恭喜,你截获了异常 //在某些设置超时处理程序中 } },超时 } 您的测试代码触发了在Messetime OutCallback中的错误,完成了;
}正如我所写的,它不能转换为future/async,因为它返回另一个对象,用户可以在该对象上操作链接case调用。case中的异常仅用于库用户的调试原因,我不能因为测试而牺牲好的API。@menfon无法测试的API不是好的API。这不仅与测试有关,而且用户也不能用简单的方法捕获异常。在案例链的末尾有一个.end部分返回一个承诺怎么样?用户不应该捕捉到这个异常。此测试的全部目的是确保调用end-如果未调用,则用户可以启用调试模式,例如,当不在生产构建中时,它将使应用程序崩溃,除非在构建最后一个案例一段时间后调用end。它并不意味着从API中可见。这将总是失败的,因为case永远不会同步抛出。我有你的方法,但我无法使它工作。future似乎无法捕获prom中setTimeout部分的异常。从未调用catch。它给出的结果与没有未来的尝试相同-在setTimeout中出现未捕获的异常时崩溃。@menfon OK,所以基本上我做了更多的作业。基本问题源于这样一个事实:您正在抛出一个错误,这是异步函数中处理问题的一种同步方式。一般的最佳实践是将错误传递回回调或通过拒绝的承诺。但是,.then或.catch块中的代码将把未捕获的错误转换为承诺拒绝。我认为它会在我以前从未尝试过的Promise body中工作,因为异步代码中的一个未捕获抛出错误对我来说意味着我没有正确地构造底层函数,但显然不是……鉴于您代码的当前结构,ComFreek的答案是最正确的。为了捕获并“提示”抛出的同步异常,它需要在.then块中发生。.then块需要在中返回一个承诺
但是,无法在承诺体中捕获抛出的错误。所以基本上答案是,不应该在异步代码中抛出同步异常;javascript要求将错误传递到回调并在那里进行处理,或者要求函数“promisified”并在出现错误时拒绝。您的应用程序代码已损坏,应进行修复以正确传播错误,不仅用于测试,而且。。。好吧,做个好代码。不,它没有坏。抛出错误不是API的一部分,它只是一种可选的方式,可以突出显示出被他搞砸了的库用户并忘记执行链类型脚本,但无法静态地检测到这一点。异常永远不会发生。仅仅为了一个干净的测试,在可用点之外引入庞然大物的冗长是愚蠢的。库的一个要点是什么,服务于库用户=简洁、好用的API,还是有漂亮、容易清理的测试?请不要下一次泛化,除非你们知道所有的事实。我可能不理解这个问题,但我仍然认为抛出只能由全局异常处理程序捕获的异常并不是一个好的实践。你写道:抛出错误不是API的一部分——那么,如果没有像劫持globals这样的黑客,你就无法干净地测试不属于API的东西。你写道:抛出错误不是API的一部分——那么你无法干净地测试不属于API的东西‘为什么?为什么不能干净地测试是否抛出了异常,而不管它的来源是什么,Mocha内部会这样做?在我看来,这似乎是JS和/或测试框架的一个限制。此异常仅是库用户的调试工具,并非所有用户都将使用它,也不会在生产中使用它。此调试选项用作解决方案,因为如果不损坏api-,就无法在JS中检查fluent api链端。
it('invalid use', () => {
    //define the promise to run the async function
    let prom = new Promise(function(resolve,reject){
        //reject the promise if the function does not throw an error
        //note I am assuming that the callback won't run if the error is thrown
        //also note this error will be passed to prom.catch so need to do some test to make sure it's not the error you are looking for.
        Matcher(1).case(1, () => {return reject(new Error('did not throw'))});
    });
    prom.catch(function(err){
        try {
            expect(err).to.be.an('error');
            expect(err.message).to.not.equal('did not throw');
            //more checks to see if err is the error you are looking for
        } catch(e) {
            //err was not the error you were looking for
            return Promise.reject(e);
        }
        //tests passed
        return Promise.resolve();
    });
    //since it() receives a promise as a return value it will pass or fail the test based on the promise.
    return prom;
});