【问题标题】:Force a yielded function to error for unit test强制产生的函数出错以进行单元测试
【发布时间】:2016-10-10 00:50:53
【问题描述】:

我正在尝试对这个 Koa 中间件进行单元测试:

function * onError(next) {
    try {
        yield next
    } catch (err) {
        this.status = 500
        this.body = err.message
    }
}

我希望触发 catch 块,但我似乎无法让 yield next 导致错误。

如果这是一个非生成器方法,我会这样做:

function method (next) {
    try {
        next()
    } catch(err) {
        this.xxx = 'Error = ' + err.message
    }
}

function next() {
  throw new Error('Boom!')
}

const context = {}

method.bind(context)(next)

console.log("Expect context to contain xxx with error message")
console.log(context.xxx)

回到生成器函数,因为next 没有被调用(它被屈服),所以没有输入catch。

我可以访问next,但调用它是不够的,它会在尝试之外抛出错误:

function next() {
    throw new Error('Boom?')
}

const iter = onError(next)

const yielded = iter.next() // Moves the generator to the first, and only, yield

console.log(yielded.value) // Our next

yielded.value() // Error is thrown here, not in the generator.

那么,我要回答的问题是,我可以强制执行到 catch 块中,从而测试我的错误处理吗?

如果有任何不清楚的地方,请在 cmets 中询问。谢谢。

【问题讨论】:

  • 也许我遗漏了一些东西,因为我还没有真正深入了解生成器函数,但我看不出有任何方法 yield next 可以在规范中抛出:ecma-international.org/ecma-262/6.0/… (稍微向下滚动到“yieldAssignmentExpression”)。我看到的唯一投掷机会是评估 AssignmentExpression,但在您的示例中评估 next 不会投掷。
  • 那么如果我在try块中没有控制next的能力,就无法进入catch?
  • 我是说我对规范的解读(可能不正确)是 yield next 永远不会抛出,无论 next 函数做什么(事实上,无论它是否是完全发挥作用)。 yield next 将暂停生成器并返回 next 的值。就这样。它不会运行 next.
  • 抱歉,误读了您的第一条评论。这就是我所看到的。我试过传入一个错误、未定义和一个函数,包括普通的和生成器。正如你所说,它不会继续。

标签: javascript unit-testing ecmascript-6 generator


【解决方案1】:

在@loganfsmyth 提到iterator.throw() 之后,我想到了这个:

// Function to test
function * onError(next) {
    try {
        yield next
    } catch (err) {
        this.status = 500
        this.body = err.message
    }
}

// Context we expect to be updated in the catch block
const context = {}

// Get the generator
const iter = onError.bind(context)()

// Move generator to first yield
iter.next()

// Pass an error into the generator
iter.throw(err)

// Check the context
expect(context.status).to.equal(500)

我曾尝试在迭代器上调用 thrownext 的其他组合,但不是这个。

内联 cmets 解释发生了什么。

【讨论】:

    【解决方案2】:

    您需要将错误传递回生成器,例如

    try {
      yielded.value();
    } catch (e){
      iter.throw(e);
    }
    

    在生成器上调用.throw 将导致从当前暂停的yield 语句中抛出一个值。

    【讨论】:

    • 谢谢@loganfsmyth - 你提示我回去再试一次throw
    猜你喜欢
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    相关资源
    最近更新 更多