>执行XHR或
>写入数据库
我该怎么做呢?我目前的想法是,当我在测试配置中启动Meteor服务器时,我应该用虚拟集合替换我的集合(通过传递新的Meteor.Collection(null))并在服务器端运行我的单元测试,调用Meteor.call ()依次从那里开始我的每一个方法.我不完全确定我是如何启动测试的,可能我想在我的应用程序中构建一个自定义/测试URL来激活它们.这种方法看起来合理吗?是否有任何库/包可以使我的方法的单元测试更容易?
解决方法
首先,在我的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 [“test”]时才会运行此代码,我可以在本地运行测试时执行此操作,但在生产中应该永远不会这样.然后它在“tests”目录中搜索javascript或coffeescript文件(在我的实现中不搜索子目录,但是很容易添加它)并将它们添加到mocha实例中.我在这里使用了优秀的mocha javascript测试库,并结合了chai断言库.
所有这些代码都包含在Meteor.startup调用中,以便我的单元测试在服务器启动时运行.这是特别好的,因为每当我更改任何代码时,Meteor都会自动重新运行我的测试.由于决定隔离数据库而不执行XHR,我的测试在几毫秒内运行,所以这不是很烦人.
对于测试本身,我需要做
chai = require("chai") should = chai.should()
引入断言库.但是,仍有一些棘手的问题需要解决.首先,如果Meteor方法调用未包含在光纤中,则它们将失败.我目前没有很好的解决这个问题的方法,但我创建了itShould函数来替换mocha的it函数并将测试体包裹在Fiber中:
# 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()函数仅适用于客户端发起的请求.我实际上已经针对Meteor提交了a bug,看看他们是否可以为这个问题提供更好的解决方案,但是现在我只是用我自己的版本替换该功能进行测试:
realUserIdFn = null before -> realUserIdFn = Meteor.userId Meteor.userId = -> "123456" after -> Meteor.userId = realUserIdFn
这种方法适用于Meteor的某些部分,但不适用于所有部分.例如,我还没有找到一种方法来测试调用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