測試產生器

請继续阅读,以深入了解 Yeoman 添加的測試輔助工具,幫助減輕單元測試產生器的負擔。

以下範例假設您在 BDD 模式下使用 Mocha。整體概念應該很容易套用在您選擇的單元測試框架。

整理測試

保持測試簡單且易於編輯非常重要。

通常整理測試的最佳方法是將每個產生器和子產生器分為其專屬的 describe 區塊。然後,為產生器接受的每個選項新增一個 describe 區塊。最後,對每個斷言 (或相關斷言) 使用一個 it 區塊。

在程式中,您最終應該得到類似以下的結構

describe('backbone:app', function () {
  it('generates a project with require.js', function () {
      // assert the file exist
      // assert the file uses AMD definition
  });

  it('generates a project with webpack');
});

測試輔助工具

Yeoman 提供測試輔助工具方法。這些方法包含在 yeoman-test 套件中。

var helpers = require('yeoman-test');

您可以在 這裡查看完整的輔助工具 API

在單元測試產生器時,最實用的方法是 helpers.run()。此方法會傳回 RunContext 執行個體,您可以在其上呼叫方法來設定目錄、模擬提示、模擬引數等。

var path = require('path');

it('generate a project', function () {
  // The object returned acts like a promise, so return it to wait until the process is done
  return helpers.run(path.join(__dirname, '../app'))
    .withOptions({ foo: 'bar' })      // Mock options passed in
    .withArguments(['name-x'])        // Mock the arguments
    .withPrompts({ coffee: false })   // Mock the prompt answers
    .withLocalConfig({ lang: 'en' }) // Mock the local config
    .then(function() {
      // assert something about the generator
    });
})

有時您可能希望建構一個測試情境,讓產生器可以在目標目錄中使用現有內容執行。這種情況下,您可以呼叫 inTmpDir(),並指定一個回呼函式,如下所示

var path = require('path');
var fs = require('fs-extra');

helpers.run(path.join(__dirname, '../app'))
  .inTmpDir(function (dir) {
    // `dir` is the path to the new temporary directory
    fs.copySync(path.join(__dirname, '../templates/common'), dir)
  })
  .withPrompts({ coffee: false })
  .then(function () {
    assert.file('common/file.txt');
  });

您也可以在回呼中執行非同步工作

var path = require('path');
var fs = require('fs-extra');

helpers.run(path.join(__dirname, '../app'))
  .inTmpDir(function (dir) {
    var done = this.async(); // `this` is the RunContext object.
    fs.copy(path.join(__dirname, '../templates/common'), dir, done);
  })
  .withPrompts({ coffee: false });

執行 Promise 會使用產生器執行的目錄來解析。如果您想使用產生器執行的暫時目錄,這會很有用

helpers.run(path.join(__dirname, '../app'))
  .inTmpDir(function (dir) {
    var done = this.async(); // `this` is the RunContext object.
    fs.copy(path.join(__dirname, '../templates/common'), dir, done);
  })
  .withPrompts({ coffee: false })
  .then(function (dir) {
    // assert something about the stuff in `dir`
  });

如果產生器呼叫 composeWith(),您可能想模擬那些依賴的產生器。使用 #withGenerators(),傳入陣列的陣列,使用 #createDummyGenerator() 作為第一個項目,並在第二個項目中指定一個名稱空間作為模擬的產生器

var deps = [
  [helpers.createDummyGenerator(), 'karma:app']
];
return helpers.run(path.join(__dirname, '../app')).withGenerators(deps);

如果您不喜歡使用承諾,可以使用發生的 'ready''error''end' 活動

helpers.run(path.join(__dirname, '../app'))
  .on('error', function (error) {
    console.log('Oh Noes!', error);
  })
  .on('ready', function (generator) {
    // This is called right before `generator.run()` is called
  })
  .on('end', done);

您也可以將產生器匯入為模組來執行。如果產生器的原始程式碼經過轉譯,此作法會很有用。

您需要為 run 提供以下設定

  • resolved:產生器的路徑,例如 ../src/app/index.js
  • namespace:產生器的名稱空間,例如 mygenerator:app
var MyGenerator = require('../src/app');

helpers.run(MyGenerator, { 
  resolved: require.resolve(__dirname, '../src/app/index.js'),
  namespace: 'mygenerator:app'
});

斷言輔助工具

Yeoman 會使用產生器相關的斷言輔助工具延伸 內建的斷言模組。您可以在 yeoman-assert 資源庫 上看到斷言輔助工具的完整清單。

需要斷言輔助工具

var assert = require('yeoman-assert');

斷言檔案存在

assert.file(['Gruntfile.js', 'app/router.js', 'app/views/main.js']);

assert.noFile() 會斷言相反的結果。

斷言檔案內容

assert.fileContent('controllers/user.js', /App\.UserController = Ember\.ObjectController\.extend/);

assert.noFileContent() 會斷言相反的結果。