测试生成器

继续阅读以了解 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);

如果您不喜欢 promises,可以使用发出的 '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 使用与生成器相关的断言助手扩展了 原生 assert 模块。您可以在 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() 断言相反。