2013-03-03 53 views
8

我爲我的應用程序編寫了一些Meteor方法,其中包含各種業務邏輯塊。現在我想爲這些方法編寫單元測試。通過單元測試,我的具體內容是快速測試,其並不:我該如何單元測試我的流星方法?

  • 執行XHR時或
  • 寫入數據庫

我怎麼能去這樣做?我目前的想法是,當我在測試配置中啓動Meteor服務器時,我應該使用虛擬集合(通過new Meteor.Collection(null))替換我的集合,並讓我的單元測試在服務器端運行,並在每個我的每個節點上調用Meteor.call方法從那裏依次。我不完全確定如何開始測試,可能我想在自己的應用程序中創建一個自定義的/tests網址,並將它們關閉。這種方法看起來是否合理?是否有任何圖書館/軟件包會使我的方法更容易編寫單元測試?

回答

1

好的,這是我想出的單元測試我的方法。我會第一個承認在這方面有很大的提升空間!

首先,我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 
0

我一直在使用jasmine來測試我正在處理的一個更大的流星應用程序。它可以做比單元測試更多的工作,並且工作得很好。關於這個的博客文章在我的待辦事項上。現在我可以給你這CoffeeScript:

if were_testing() 
    describe 'something', -> 
    it 'should be greater than 0', -> 
     expect(theThing).toBeGreaterThan 0 

were_testing = -> document.location.pathname.replace(/^\/([^\/]*).*$/, '$1') == 'tests' 

jasmine_test = -> 
    jasmineEnv = jasmine.getEnv() 
    jasmineEnv.updateInterval = 1000 

    htmlReporter = new jasmine.HtmlReporter() 
    jasmineEnv.addReporter htmlReporter 

    jasmineEnv.execute() 

此代碼在瀏覽器中運行。如果您想編寫腳本,可以在casperjs實例中運行它。由於它經歷了客戶端上的Meteor初始化,它將執行XHR和數據庫查詢,但是您可以輕鬆編寫不會做任何額外查詢的測試。或者編寫訪問時觸發的函數的子集/ unittests

我們的東西尚未投入生產,但deployscript只是刪除上面的茉莉花代碼和所有*.spec.coffee文件。

我想將它插入Jenkins以獲得適當的持續集成設置,但沒有時間設置Jenkins以上的基礎知識。我也玩過使用casperjs進行無頭瀏覽,效果很好。

您也可以採取不同的方法,將您的測試代碼放入tests/(未由Meteor執行),然後使用require。我很快嘗試過,發現它很乏味。

+0

我可能不會理解這一點,但它看起來像這段代碼會在瀏覽器中運行,對吧?在這種情況下,我認爲單獨測試方法變得非常困難。除非有特別的事情發生,否則你的方法調用將會進行XHR和數據庫寫入等等,不是嗎? – 2013-03-04 20:53:51