Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 如何对meteor方法进行单元测试?_Database_Unit Testing_Meteor - Fatal编程技术网

Database 如何对meteor方法进行单元测试?

Database 如何对meteor方法进行单元测试?,database,unit-testing,meteor,Database,Unit Testing,Meteor,我已经为我的应用程序编写了一些Meteor方法,其中包含各种业务逻辑块。现在我想为这些方法编写单元测试。关于单元测试,我特别指的是快速测试,它不: 执行xhr或 写入数据库 我该怎么做呢?我目前的想法是,当我在测试配置中启动Meteor服务器时,我应该用虚拟集合替换我的集合(通过传递new Meteor.Collection(null)),并让我的单元测试在服务器端运行,然后依次调用我的每个方法上的Meteor.call()。我不完全确定如何启动这些测试,可能我想在我的应用程序中构建一个自定

我已经为我的应用程序编写了一些Meteor方法,其中包含各种业务逻辑块。现在我想为这些方法编写单元测试。关于单元测试,我特别指的是快速测试,它不:

  • 执行xhr或
  • 写入数据库
我该怎么做呢?我目前的想法是,当我在测试配置中启动Meteor服务器时,我应该用虚拟集合替换我的集合(通过传递
new Meteor.Collection(null)
),并让我的单元测试在服务器端运行,然后依次调用我的每个方法上的Meteor.call()。我不完全确定如何启动这些测试,可能我想在我的应用程序中构建一个自定义的
/tests
URL来启动它们。这种做法合理吗?是否有任何库/包可以使我的方法编写单元测试变得更容易?

我一直在使用它来测试我正在开发的更大的Meteor应用程序。它可以做的远不止单元测试,而且一直工作得相当好。我的待办事项列表上有一篇关于这一点的博客文章。现在我可以给你这个咖啡剧本:

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时触发的函数子集

我们的东西还没有投入生产,但是部署脚本只是删除了上面的jasmine代码和所有
*.spec.coffee
文件

我想将其插入Jenkins以获得适当的持续集成设置,但除了基本设置外,我还没有时间设置Jenkins。我还使用casperjs进行无头浏览,效果非常好


您还可以采取另一种方法,将测试代码放入
测试/
(不是由Meteor执行),然后使用
require
。我很快尝试了这个方法,发现它非常乏味。

好吧,下面是我提出的单元测试方法。我会第一个承认在这方面有很大的改进空间

首先,在我的
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
实例中。我在这里使用优秀的javascript测试库,并结合断言库

所有这些代码都封装在一个
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”)
进行收藏即可。然后,在测试中,您可以在函数模拟集合之前使用

realCollection = null
before ->
  realCollection = myApp.Collection
  myApp.Collection = new Meteor.Collection(null)
after ->
  myApp.Collection = realCollection
这样,您的集合在测试运行期间会被模拟出来,但随后会被还原,以便您可以正常与应用程序交互。其他一些东西也可以通过类似的技术来模拟。例如,全局
Meteor.userId()
函数仅适用于客户端启动的请求。事实上,我已经向Meteor提交了申请,看看他们是否能提供更好的解决方案,但现在我只是用我自己的测试版本替换该功能:

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和数据库写入之类的操作,不是吗?