测试 Generators

Read on to learn more about the testing helpers Yeoman add to ease the pain of unit testing a generator.

The examples below assume you use Mocha in BDD mode. The global concept should apply easily to your unit testing framework of choice.

Organizing your tests

It is important to keep your tests simple and easily editable.

Usually the best way to organize your tests is to separate each generator and sub-generator into its own describe block. Then, add a describe block for each option your generator accept. And then, use an it block for each assertion (or related assertion).

The code running the generator should be located in a before or beforeEach block - it usually doesn't belong with your assertions.

In code, you should end up with a structure similar to this:

describe('backbone:app', function () {
  describe('when using require.js', function () {
    before(function () {
      // Mock the options, set up an output folder and run the generator
    });

    it('generate a router.js file', function () {
      // assert the file exist
      // assert the file uses AMD definition
    });

    it('generate a view file');
    it('generate a base controller');
  });
});

Test helpers

Yeoman provide test helpers methods. They're contained inside the yeoman-test package.

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

You can check the full helpers API here. These methods will usually be run inside a before block.

The most useful method when unit testing a generator is helpers.run(). This method will return a RunContext instance on which you can call method to setup a directory, mock prompt, mock arguments, etc.

var path = require('path');

before(function () {
  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
    .toPromise();                   // Get a Promise back for when the generator finishes
})

Sometimes you may want to construct a test scenario for the generator to run with existing contents in the target directory. In which case, you could invoke inTmpDir() with a callback function, like so:

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 })
  .toPromise();

You can also perform asynchronous task in your callback:

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 })
  .toPromise();

When using .toPromise(), the returned Promise will resolve with the directory that the generator was run in. This can be useful if you want to use a temporary directory that the generator was run in:

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 })
  .toPromise()
  .then(function (dir) {
    // assert something about the stuff in `dir`
  });

If your generator calls composeWith(), you may want to mock those dependent generators. Using #withGenerators(), pass in array of arrays that use #createDummyGenerator() as the first item and a namespace for the mocked generator as a second item:

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

If you hate promises, you can use the 'ready', 'error', and 'end' Events emitted:

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);

Assertions helpers

Yeoman extends the native assert module with generator related assertions helpers. You can see the full list of assertions helpers on the yeoman-assert repository.

Require the assertion helpers:

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

Assert files exists

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

assert.noFile() assert the contrary.

Assert a file content

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

assert.noFileContent() assert the contrary.

发现一个错误?一个不清楚的例子?通过派生并发送你的修改和建议来帮助我们改进文档。改善此页面!