【问题标题】:Testing Restify services with Mocha-Cakes, and Coffescript, use of done() in async causes timeout issues使用 Mocha-Cakes 和 Coffescript 测试 Restify 服务,在异步中使用 done() 会导致超时问题
【发布时间】:2014-04-30 11:08:40
【问题描述】:

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

我对 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 应该 -R spec --compilers 咖啡:咖啡脚本/注册

功能:帐户 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 通过 (6s) 1 等待 3 失败

1) 功能:账户 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) 功能:账户 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) 功能:账户 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-cakes restify testing coffeescript mocha.js restify mocha-cakes


    【解决方案1】:

    我也不熟悉摩卡蛋糕。我正在使用 mocha/(lit)coffee 来测试 restify。我发现将我的调用封装在 Promise 中很方便,因为最新的 mocha 是 Promise-aware 的。然后我不必为“完成”而烦恼。另请注意,您可能需要调用 res.end() 或 res.resume()(请参阅this explanation

    仅用于“获取”:

    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])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-06
      • 2020-03-26
      • 1970-01-01
      • 2020-10-23
      • 1970-01-01
      • 2018-02-23
      • 2018-08-19
      • 2013-11-23
      相关资源
      最近更新 更多