8

私は、ビジネスロジックのさまざまなチャンクを含むアプリケーション用にいくつかのMeteorメソッドを作成しました。次に、これらのメソッドの単体テストを作成します。単体テストとは、具体的には次のことを行わない高速テストを意味します。

  • XHRを実行するまたは
  • データベースに書き込む

どうすればこれを行うことができますか?私の現在の考えでは、テスト構成でMeteorサーバーを起動するときは、コレクションをダミーコレクションに置き換え(合格することnew Meteor.Collection(null)で)、サーバー側で単体テストを実行し、各メソッドでMeteor.call()を呼び出す必要があります。そこから順番に。/testsテストを開始する方法が完全にはわかりません。おそらく、アプリケーションにカスタムURLを作成して、テストを開始したいと思います。このアプローチは合理的だと思いますか?メソッドの単体テストを簡単に作成できるライブラリ/パッケージはありますか?

4

2 に答える 2

2

さて、これが私のメソッドをユニットテストするために思いついたものです。これには改善の余地がたくさんあることを最初に認めます!

まず、私の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メソッドの呼び出しは、ファイバーにラップされていない場合は失敗します。現在、この問題に対する優れた解決策はありませんが、itShouldmochaの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()関数はクライアントが開始したリクエストに対してのみ機能します。私は実際にMeteorに対してバグを報告して、この問題のより良い解決策を提供できるかどうかを確認しましたが、今のところ、テスト用に関数を自分のバージョンに置き換えています。

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
于 2013-03-09T18:31:59.913 に答える
0

私は、作業中のより大きなMeteorアプリケーションをテストするためにジャスミンを使用しています。ユニットテスト以上のことができ、かなりうまく機能しています。これに関するブログ投稿は私のtodolisにあります。今のところ私はあなたにこの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。私はすぐにこれを試しましたが、かなり退屈でした。

于 2013-03-04T19:59:51.610 に答える