javascript - 在 yeoman 生成器中对单个方法进行单元测试的推荐方法是什么?

标签 javascript yeoman-generator

doc for yeoman unit testing似乎面向集成测试,即运行整个生成器,然后检查产​​生的副作用,即某些文件是否存在。为此,您可以使用 helpers.run()

这一切都很好,但我也希望能够单元测试单个方法(或“优先级”)并测试生成器的内部状态,即内部变量。我之前已经能够通过使用 createGenerator 来做到这一点,如下所示:

subAngularGenerator = helpers.createGenerator('webvr-decorator:sub-angular', [
  path.join(__dirname, '../generators/sub-angular')
  ],
  null,
 {'artifacts': artifacts, appName: APP_NAME, userNames: userNames,
 });

它没有 RunContext,但我通常可以向该结构添加足够的内容以便它能够运行。例如:

   // mixin common class
    _.extend(subAngularGenerator.prototype, require('../lib/common.js'));

    // we need to do this to properly feed in options and args
    subAngularGenerator.initializing();

    // override the artifacts hash
    subAngularGenerator.artifacts = artifacts;

    // call method
    subAngularGenerator._injectDependencies(fp, 'controller', ['service1', 'service2']);

这允许我测试内部状态:

var fileContents = subAngularGenerator.fs.read(fp);
var regex = /\('MainCtrl', function \(\$scope, service1, service2\)/m;

assert(regex.test(fileContents));

只要该方法是基本的 javascript,例如 for/next 循环等,就可以正常工作。如果该方法使用任何“this”变量,例如 this.async(),我会得到'this.async' is not a function

    initialPrompt: function () {

      var prompts = [];
      var done = this.async(); //if this weren't needed my ut would work
...

我可以手动添加一个虚拟 this.async,但随后我会遇到其他错误,例如“没有可用的商店”:

AssertionError: A store parameter is required
  at Object.promptSuggestion.prefillQuestions (node_modules/yeoman-generator/lib/util/prompt-suggestion.js:98:3)
  at RunContext.Base.prompt (node_modules/yeoman-generator/lib/base.js:218:32)
  at RunContext.module.exports.AppBase.extend.prompting.initialPrompt (generators/app/index.js:147:12)
  at Context.<anonymous> (test/test-app.js:158:42)

我尝试创建一个 runContext,然后将我的生成器添加到其中:

var helpers = require('yeoman-generator').test;
// p.s. is there a better way to get RunContext?
var RunContext = require('../node_modules/yeoman-generator/lib/test/run-context');

  before(function (done) {

    appGenerator = helpers.createGenerator('webvr-decorator:app', [
      path.join(__dirname, '../generators/app')
    ],
                                           null,
    appName: APP_NAME, userNames: userNames,
  {});

 app = new RunContext(appGenerator); //add generator to runContext
});

 app.Generator.prompting.initialPrompt(); //gets async not defined

但这也遇到了同样的问题。

我的理论是问题与“this”上下文有关。通常该方法与整个生成器的“this”上下文一起运行(它有一个 this.async 等),但是当我单独运行该方法时,“this”上下文只是方法/函数本身的上下文(它没有在其上下文中是异步的)。如果这是真的,那么这实际上更像是一个 JavaScript 问题,而不是一个 yeoman 问题。

似乎应该有一种简单的方法来对依赖于生成器上下文的各个方法进行单元测试,例如对 this.async 的调用。我提到了generator-node作为最佳实践的示例,但它似乎只是在进行集成测试。

有没有人有更好的想法,或者我需要继续研究 JavaScript 技术吗?

非常感谢。

最佳答案

我能够让它工作,但这完全是一个黑客行为。我能够使用必要的工件来装饰 RunContext,然后使用 apply,将生成器放入 RunContext 的上下文中:

  var appGenerator;
  var app;

  before(function (done) { 
    // create a generator 
    appGenerator = helpers.createGenerator('webvr-decorator:app', [
      path.join(__dirname, '../generators/app')
    ],
                                           null,
 appName: APP_NAME, userNames: userNames,
                                           {}
                                          );
    // get a RunContext
    app = new RunContext(appGenerator);
    // the following did *not* work -- prompts were not auto-answered
    app.withPrompts({'continue': true, 'artifactsToRename': {'mainCtrl' : 'main'}});

    //add the following functions and hashes from the generator to the RunContext
    app.prompt = appGenerator.prompt;
    app._globalConfig = appGenerator._globalConfig;
    app.env = appGenerator.env;

    // the following two lines are specific to my app only
    app.globals = {};   
    app.globals.MAIN_CTRL = 'main';

    done();
  });

 it('prompting works', function () {
    // Run the generator in the context of RunContext by using js 'call'
    appGenerator.prompting.initialPrompt.call(app);
}

我不再收到任何“缺少功能”消息,但不幸的是,单元测试不会自动提供提示,因此该方法停止等待某些内容来提供提示。

最大的“ secret ”是使用 apply 进行调用,您可以使用它来覆盖默认的 this 上下文。我将生成器放在 RunContext 的上下文中,这验证了我的理论,即问题在于不正确的上下文中。

我认为有更好的方法可以做到这一点,但我完全错过了一些东西。但我想我至少应该记录一下我必须做些什么才能让它发挥作用。最后,我将变量初始化代码从“提示”方法移至“初始化”方法,并且由于我的“初始化”方法没有 Yeoman 运行时依赖项,因此我能够使用一个没有 RunContext 的简单生成器。但在这种情况下,这只是偶然的。一般情况下,我仍然想找出调用单个方法的正确方法。

关于javascript - 在 yeoman 生成器中对单个方法进行单元测试的推荐方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34918581/

相关文章:

javascript - 警报显示并在一段时间后消失

javascript - 将数组转换为带有数组的对象

Javascript - 单击时,检查元素是否具有带值的属性

node.js - npm install without symlinks 选项不起作用

javascript - 扩展 Angular yeoman 生成器

node.js - 使用 npm 开关在 Windows 下运行 Yeoman Generator

node.js - 使用 yeoman 生成终极种子时出错

yeoman 错误 对等点无效 对等点生成器-webapp@0.5.0 想要@>=1.2.0

javascript - onclick 事件仅适用于第一个产品,不适用于其他获取的数据

javascript - 使用代理访问自定义元素的数据集