使用 Jasmine 和 Rails 3.1 测试 Coffeescript

Posted

技术标签:

【中文标题】使用 Jasmine 和 Rails 3.1 测试 Coffeescript【英文标题】:Testing Coffeescript with Jasmine and Rails 3.1 【发布时间】:2011-12-20 22:48:53 【问题描述】:

假设我在 Coffeescript 有一堂课:

class MyGame
   constructor: () ->
      @me = new Player
      @opponents = [new Player, new Player]

想在 Jasmine 中测试:

describe "MyGame", ->
   beforeEach ->
     window.game = new MyGame

   it "should have two players", ->
      expect(window.game.opponents.length).toEqual 2

但我收到错误 TypeError: Result of expression 'window.game.opponents' [undefined] is not an object.?

window.game 方法在我看来也很尴尬。如果我尝试将其定义为 @game = new MyGame 我会收到错误 ReferenceError: Can't find variable: MyGame 但我想这与 Coffeescript 的包装方式有关?

更新:这个问题看起来更像是一个参考问题,如上所述。我正在使用guard-jasmine 运行,看起来像

guard 'jasmine', :all_on_start => false, :all_after_pass => false do
  watch(%rapp/assets/javascripts/(.+)\.(js\.coffee|js))  |m| "spec/javascripts/#m[1]_spec.#m[2]" 
  watch(%rspec/javascripts/(.+)_spec\.(js\.coffee|js))   |m| "spec/javascripts/#m[1]_spec.#m[2]" 
  watch(%rspec/javascripts/spec\.(js\.coffee|js))        "spec/javascripts" 
end

我的jasmine.yml 文件有:

src_files:
    - "app/assets/**/*.js"
    - "app/assets/**/*.coffee"
spec_files: 
    - '**/*[sS]pec.js.coffee' 
asset_pipeline_paths: 
    - app/assets 
    - spec/javascripts

我得到了一个ReferenceError: Can't find variable: MyGame,所以我认为它要么是 Rails 3.1 资产管道的东西,要么是 Coffeescript 包装对象的方式。

【问题讨论】:

Player有同样的问题吗? 这只是 Jasmine 的问题吗?网站的代码怎么样?另外,也许这有帮助:***.com/questions/6150455/… 【参考方案1】:

尝试使用 @ 运算符定义您的咖啡脚本类:

class @MyGame
   constructor: () ->
      @me = new Player
      @opponents = [new Player, new Player]

这将允许您从任何地方访问该类,例如从您的 jasmine 测试中,并且您可以摆脱将测试变量附加到窗口:

describe "MyGame", ->
   beforeEach ->
     @game = new MyGame

   it "should have two players", ->
      expect(@game.opponents.length).toEqual 2

这样做的原因是,coffeescript 通过将所有内容包装在一个闭包中来避免引入全局变量。不幸的是,这对于面向对象的代码可能是不可取的。使用@ 运算符将类定义附加到全局this(即窗口),从而允许您根据需要实例化您的类。你现在可能在你的全球空间里有一些全球变量,你的课程,但对我来说这是一个不错的权衡。希望这会有所帮助!

【讨论】:

感谢您的跟进。这当然是最好的解决方案,也是我最终要做的。【参考方案2】:

我不愿意接受通过在所有主干类前面使用 @ 符号来修改代码的命名空间,所以我挖掘了更多内容,对我有用的解决方案是在我的spec/javascripts/spec.js.coffee 文件

#= require application

【讨论】:

虽然这可以工作,但它似乎......对于单元测试来说是笨拙的。并非所有测试都需要应用程序清单所需的每个 js 文件。 IMO,您应该只需要每次测试所需的文件。【参考方案3】:
window.game = () -> new MyGame

这将分配一个函数来返回一个新的 MyGame 给 window.game。您不只是直接想要新实例吗?

window.game = new MyGame

window.game 方法对我来说也很尴尬。

这个怎么样

describe "MyGame", ->
   game = null

   beforeEach ->
     game = new MyGame

   it "should have two players", ->
      expect(game.opponents.length).toEqual 2

【讨论】:

在这种情况下,我得到一个ReferenceError: Can't find variable: MyGame。顺便提一句。我正在使用 Rails 3.1,我的 jasmine.ymlsrc_files: - "app/assets/**/*.js" - "app/assets/**/*.coffee" 和资产管道设置正确。 MyGame 如何对测试文件(或一般外部世界)可见?不幸的是,没有真正的标准,我不能代表 Rails。我使用 CommonJS,我会在文件顶部有MyGame = require 'models/game'。但我不知道这是否适用于您的设置。 我已经更新了这个问题。正如您所描述的,我认为这更像是一个参考问题,我猜它与 Rails 3.1 资产管道有关。【参考方案4】:

例如,我通过将每个类定义为class window.MyGame 来解决了这个问题。在规范文件中,我将#= require my_file_name 放在顶部。

此外,我将jasminerice.js.coffeejquery.js 都放在了app/assets/javascripts 中。这可能不是最好的解决方案,因为我认为它们应该放在spec/javascripts/helpers 中,因为我的spec.js.coffee 的内容是#=require_tree ./

我知道这不是很优雅,但它可能会帮助处于相同情况的其他人。 @Thilo 感谢您的投入。

【讨论】:

以上是关于使用 Jasmine 和 Rails 3.1 测试 Coffeescript的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails 5.1 和 Vue.js 2.4.x – 使用 Karma、Jasmine 进行测试 – 如何安装?

使用 Jasmine 单独测试 Marionette 模块

基于karma和jasmine的Angularjs 单元测试

Angularjs 基于karma和jasmine的单元测试

在 Rails 3.1 中使用 Capybara、Rspec 和 Selenium 进行测试时登录失败

使用 Rspec 测试 Rails 3.1 可安装引擎