使用 Mocha-Cakes 和 Coffescript 测试 Restify 服务,在异步中使用 done() 会导致超时问题

标签 testing coffeescript mocha.js restify mocha-cakes

我遇到了一些 的计时问题针对 运行的测试脚本服务。我正在使用 Restify JSON 客户端发出调用,它使用回调而不是 promise 。我已将 done 函数传递给我的 GivenWhen,这样我就可以对这些异步调用执行必要的阻止,从而防止不一致的测试套件运行(没有完成,这是一个折腾,以及有多少 ThenAnd 将通过。

我对 coffescript 相当熟练,在 mocha/mocha-cakes 方面只是个新手,所以我的代码肯定有问题。下面是几个失败的测试用例的示例:

require 'mocha-cakes'
should = require 'should'
restify = require 'restify'


Feature "Account API",
  "In order to have control over structured Account documents",
  "as a consumer of investment account information,",
  "I need a RESTful service API.", ->

    Scenario "GET /account/:userid", ->

      client = restify.createJSONClient
        url: "http://localhost:8080",
        version: "*"

      _e1 = null
      _r1 = null

      _e2 = null
      _r2 = null
      _d2 = null

      # GET non-existent account
      Given "I have not yet created the Account", ->
      When "I request the Account", (done) ->
        client.get "/account/99", (err, req, res, obj) ->
          _e1 = err
          _r1 = res
          done()
          err

      Then "it should respond with an error", ->
        _e1.should.be.ok
      And "the status code should be 404", ->
        _r1.should.have.status 404


      # GET existent account
      Given "I have created the Account", (done) ->
        client.post "/account", { userId: 1, accountType: 0, accountCategories: [], beneficiaries: [], accountOwner: { firstName: "Test", lastName: "User" } }, (err) ->
          done()
          err

      When "I request the Account", (done) ->
        client.get "/account/1", (err, req, res, obj) ->
          _e2 = err
          _r2 = res
          _d2 = obj
          done()
          err

      Then "it should responond with a document", ->
        _d2.should.be.ok
      And "it should have the userId 1", ->
        _d2.userId.should.eql 1
      And "it should have an accountOwner property", ->
        _d2.accountOwner.should.be.ok
      And "the status code should be 200", ->
        _r2.should.have.status 200

当我运行它时,我的输出总是如下:

c:\Development\Clients\Pensco\AngularJS\Pensco\newaccountwizard.api>mocha test/AccountAPITests.coffee -r should -R spec --compilers coffee:coffee-script/register

Feature: Account API

    In order to have control over structured Account documents
    as a consumer of investment account information,
    I need a RESTful service API.


Scenario: GET /account/:userid
  ◦
    - ◊ Given: I have not yet created the Account (pending)
  ◦
    1)  When: I request the Account
  ◦
    √  Then: it should respond with an error
  ◦
    √   And: the status code should be 404
  ◦
    2) Given: I have created the Account
  ◦
    3)  When: I request the Account
  ◦
    √  Then: it should responond with a document
  ◦
    √   And: it should have the userId 1
  ◦
    √   And: it should have an accountOwner property
  ◦
    √   And: the status code should be 200

6 passing (6s) 1 pending 3 failing

1) Feature: Account API

    In order to have control over structured Account documents
    as a consumer of investment account information,
    I need a RESTful service API.

Scenario: GET /account/:userid ◦  When: I request the Account:
 Error: timeout of 2000ms exceeded
at [object Object].<anonymous> (C:\Users\Jon\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:139:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

2) Feature: Account API

    In order to have control over structured Account documents
    as a consumer of investment account information,
    I need a RESTful service API.

Scenario: GET /account/:userid ◦ Given: I have created the Account:
 Error: timeout of 2000ms exceeded
at [object Object].<anonymous> (C:\Users\Jon\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:139:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

3) Feature: Account API

    In order to have control over structured Account documents
    as a consumer of investment account information,
    I need a RESTful service API.

Scenario: GET /account/:userid ◦  When: I request the Account:
 Error: timeout of 2000ms exceeded
at [object Object].<anonymous> (C:\Users\Jon\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:139:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

现在,我知道我通过 client.get/client.post 进行的 REST 调用几乎是瞬间发生的。当我删除完成并在没有它们的情况下运行时,除了重新启动我的 restify 服务服务器后的第一次运行外,通常只有第一次或第二次 Then/And 失败,其余成功。可能有几毫秒的计时问题,但绝对不是 2000 毫秒。我很好奇为什么当我输入 done() 调用时我的 Givens 和 Whens 突然开始超时。

我很确定我误解了 mocha-cakes 如何将 coffescript Feature->Scenario->Given/When->Then/And/... 转换为 describe/it 调用。我怀疑 done 应用的范围不知何故比 mocha-cakes 脚本结构的性质似乎要大...我只是不确定该范围到底是什么。

最佳答案

我也不熟悉 Mocha 蛋糕。我正在使用 mocha/(lit)coffee 来测试 restify。我发现用 promises 包装我的调用很方便,因为最新的 mocha 是 promise-aware 的。这样我就不必为“完成”而烦恼了。另请注意,您可能需要调用 res.end() 或 res.resume()(参见 this explanation)

对于“GET”:

Promise = require('bluebird')  # or whatever, I presume
port = 8776                    # ditto

getHttpJson = (addr)->
  addr = normalizeUrl(addr)
  new Promise ( resolve, reject )->
    req = http.get(addr, _completeResponse(resolve) )
      .on( 'error', reject )
    req.end()

一般情况:

requestHttpJson = (method, addr, data)->
  if data?
    data = JSON.stringify(data)
  urlBits = getUrlBits(addr)
  new Promise (resolve, reject)->
    req = http.request(
      method: method
      headers: {
        "Content-Type": "application/json" }
      hostname: urlBits.hostname
      port: urlBits.port
      path: urlBits.pathname
    , _completeResponse(resolve) )
    req.on( 'error', reject )
    if data?
      req.write( data )
    req.end()

postHttpJson = (addr, data)->
  requestHttpJson('POST', addr, data)
putHttpJson = (addr, data)->
  requestHttpJson('PUT', addr, data)
deleteHttpJson = (addr, data)->
  requestHttpJson('DELETE', addr, data)

将地址分解成组件并添加默认值。 (“端口”是一个全局模块。)

getUrlBits = (addr)->
  bits = url.parse(addr)
  bits.port = bits.port || port
  bits.hostname = bits.hostname || 'localhost'
  bits.protocol = bits.protocol || 'http'
  return bits

normalizeUrl = (addr)->
  url.format(getUrlBits(addr))

解析请求体和解析的实用程序。

_completeResponse = (resolve)->
  (res)->
    body = []
    res.on 'data', (data)->
      body.push data
    res.on 'end', ->
      body = body.join ''
      content = if body == '' then null else JSON.parse(body)
      resolve([res,content])

关于使用 Mocha-Cakes 和 Coffescript 测试 Restify 服务,在异步中使用 done() 会导致超时问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23299228/

相关文章:

asp.net - 为 asp.net web 应用程序编写单元测试

ruby-on-rails - 用 capybara 填充隐藏区域

javascript - 如何将 javascript 字符串拆分成最多 2 个部分?

javascript - Rails - 莫里斯图表未出现

node.js - 在 Mocha 测试中的 for 循环中进行顺序 Mongoose 查询

javascript - 如何使用 visual studio 代码调试 javascript 中的 mocha 测试?

javascript - 如何解决 'Assertions require every name in the call target to be declared with an explicit type annotation.ts(2775)' ?

testing - 如何使用带有 expresso/jasmine/<other> 的节点测试客户端 coffeescript/js

java - 开始使用 TestFx

coffeescript - 即使存在 coffeescript 编译错误,我如何保持 grunt 服务器运行?