好的,這是我想出的單元測試我的方法。我會第一個承認在這方面有很大的提升空間!
首先,我server.coffee
文件我有以下代碼:
Meteor.startup ->
return unless Meteor.settings["test"]
require = __meteor_bootstrap__.require
require("coffee-script")
fs = require("fs")
path = require("path")
Mocha = require("mocha")
mocha = new Mocha()
files = fs.readdirSync("tests")
basePath = fs.realpathSync("tests")
for file in files
continue unless file.match(/\.coffee$/) or file.match(/\.js$/)
continue if file[0] == "."
filePath = path.join(basePath, file)
continue unless fs.statSync(filePath).isFile()
mocha.addFile(filePath)
mocha.run()
首先這個代碼只運行。如果Meteor.settings [「測試」]已經定義,我可以當我運行做我的測試在本地,但在生產中永遠不會是真的。然後它在「測試」目錄中搜索javascript或coffeescript文件(在我的實現中不搜索子目錄,但可以很容易地添加它),並將它們添加到mocha
實例中。我在這裏使用優秀的mocha javascript測試庫,並結合chai斷言庫。
所有這些代碼被包裝在一個Meteor.startup
調用中,以便我的單元測試在服務器啓動時運行。這是非常好的,因爲每當我更改我的任何代碼時,Meteor會自動重新運行我的測試。由於決定隔離數據庫而不執行XHR,我的測試運行幾毫秒,所以這不是很煩人。
對於測試本身,我需要做的
chai = require("chai")
should = chai.should()
拉進來的斷言庫。不過,仍然有一些棘手的問題需要解決。首先,如果Meteor方法調用不包含在光纖中,它將會失敗。我目前還沒有很好的解決了這個問題,但我創建了itShould
功能,以取代摩卡的it
功能和包裹人體試驗光纖內:
# A version of mocha's "it" function which wraps the test body in a Fiber.
itShould = (desc, fn) ->
it(("should " + desc), (done) -> (Fiber ->
fn()
done()).run())
接下來是問題,進行測試用模擬集合取代我的集合。如果你遵循標準的Meteor將你的集合放入全局變量的做法,這很難做到。但是,如果您在全局對象上設置了屬性,則可以這樣做。只需通過myApp.Collection = new Meteor.Collection("name")
即可完成收藏。然後,在你的測試,你可以有一個before
功能模擬出集合:
realCollection = null
before ->
realCollection = myApp.Collection
myApp.Collection = new Meteor.Collection(null)
after ->
myApp.Collection = realCollection
這樣,你的集合嘲笑了測試運行的持續時間,但後來它的恢復,您可以與互動的通常應用通過類似的技術可以嘲笑其他一些事情。例如,全局Meteor.userId()
函數僅適用於客戶端啓動的請求。其實我已經提起針對a bug流星,看看他們是否能提供更好的解決了這個問題,但現在我只是用我自己的版本替換功能來進行測試:
realUserIdFn = null
before ->
realUserIdFn = Meteor.userId
Meteor.userId = -> "123456"
after ->
Meteor.userId = realUserIdFn
這種方法適用於一些流星的部分,但不是全部。例如,我還沒有找到一種方法來測試調用this.setUserId
的方法,因爲我不認爲有一種很好的方法來嘲笑這種行爲。但總的來說,這種方法正在爲我工作...我喜歡在更改代碼時能夠自動重新運行測試,並且單獨運行測試通常是一個好主意。在服務器上進行測試可以阻止也很方便,這使得它們在沒有回調鏈的情況下編寫起來更簡單。以下是測試的樣子:
describe "the newWidget method", ->
itShould "make a new widget in the Widgets collection", ->
widgetId = Meteor.call("newWidget", {awesome: true})
widget = myApp.Widgets.findOne(widgetId)
widget.awesome.should.be.true
我可能不會理解這一點,但它看起來像這段代碼會在瀏覽器中運行,對吧?在這種情況下,我認爲單獨測試方法變得非常困難。除非有特別的事情發生,否則你的方法調用將會進行XHR和數據庫寫入等等,不是嗎? – 2013-03-04 20:53:51