如何使用 G运行t 和 Mocha 按 mtime 顺序 运行 进行单元测试

How to run unit tests in mtime order with Grunt and Mocha

因此,当您进行 TDD 时,是否会等 运行 所有测试直到您正在处理的测试?这需要太多时间。当我匆忙时,我将测试文件重命名为 aaaaaaaaaaaaaaaa_testsomething.test.js 这样的名字,所以它是 运行 第一,我会尽快看到错误。

我不喜欢这种方法,我确信有解决方案,但我找不到。那么,使用 Mocha 以 mtime 顺序进行 运行 单元测试的最简单方法是什么?有 -sort 选项,但它仅按名称对文件进行排序。如何按修改时间排序?

这是我的 Gruntfile.js:

module.exports = function(grunt) {

  grunt.initConfig({
    watch: {
      tests: {
        files: ['**/*.js', '!**/node_modules/**'],
        tasks: ['mochacli:local']
      }
    },
    mochacli: {
      options: {
        require: ['assert'],
        reporter: 'spec',
        bail: true,
        timeout: 6000,
        sort: true,
        files: ['tests/*.js']
      },
      local: {
        timeout: 25000
      }
    }
  });

  
  grunt.loadNpmTasks('grunt-mocha-cli');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('test', ['mochacli:local']);
  grunt.registerTask('livetests', [ 'watch:tests']);

};

注意:不是重复的。我不想每次保存源代码文件时都编辑我的测试或 Gruntfile.js。我在询问如何修改 G运行t 任务,以便它首先从上次修改的 *.test.js 文件进行 运行s 测试。按时间排序单元测试,如标题所述。

简单场景:我在编辑器中打开 test1.test.js,更改它,按 Ctrl+B,它从 test1.运行s 单元测试。test.js 然后是 test4.test.js。我打开 test4.test.js,按 Ctrl+S、Ctrl+B,它从 test4.test.js 然后是 test1.test.js

运行s 测试

我正在考虑一些 G运行t 插件来首先对文件进行排序,这样我就可以把它的结果放在那里而不是 'tests/*.js' 和 grunt.config.set('mochacli.options.files', 'tests/recent.js,tests/older.js', ....); 但我找不到我可以在那里用作中间件的任何东西,不想发明 bycicle,因为我确定已经实现了一些东西。

如果您使用的是 mocha,您可以在您感兴趣的测试中设置 .only:

describe(function () {
  // these tests will be skipped
});
describe.only(function () {
  // these tests will run
})

don't want to invent bicycle as I'm sure there's something for this implemented already.

...有时你必须骑自行车;)


解决方案

这可以通过在您的 Gruntfile.js 中注册中间体 custom-task 来动态执行以下操作来实现:

  1. 使用 grunt.file.expand with the appropriate globbing 模式获取所有单元测试文件 (.js) 的文件路径。
  2. 按文件 mtime/修改日期对每个匹配的文件路径进行排序。
  3. 使用 grunt.config
  4. 使用按时间顺序排序的文件路径配置 mochacli.options.file 数组
  5. 运行 local Target defined in the mochacli Task using grunt.task.run

Gruntfile.js

按如下方式配置您的 Gruntfile.js

module.exports = function(grunt) {

  // Additional built-in node module.
  var statSync = require('fs').statSync;

  grunt.initConfig({
    watch: {
      tests: {
        files: ['**/*.js', '!**/node_modules/**', '!Gruntfile.js'],
        tasks: ['runMochaTests']
      }
    },
    mochacli: {
      options: {
        require: ['assert'],
        reporter: 'spec',
        bail: true,
        timeout: 6000,
        files: [] // <-- Intentionally empty, to be generated dynamically.
      },
      local: {
        timeout: 25000
      }
    }
  });

  grunt.loadNpmTasks('grunt-mocha-cli');
  grunt.loadNpmTasks('grunt-contrib-watch');

  /**
   * Custom task to dynamically configure the `mochacli.options.files` Array.
   * All filepaths that match the given globbing pattern(s), which is specified
   # via the `grunt.file.expand` method, will be sorted chronologically via each
   * file(s) latest modified date (i.e. mtime).
   */
  grunt.registerTask('runMochaTests', function configMochaTask() {
    var sortedPaths = grunt.file.expand({ filter: 'isFile' }, 'tests/**/*.js')
      .map(function(filePath) {
        return {
          fpath: filePath,
          modtime: statSync(filePath).mtime.getTime()
        }
      })
      .sort(function (a, b) {
        return a.modtime - b.modtime;
      })
      .map(function (info) {
        return info.fpath;
      })
      .reverse();

    grunt.config('mochacli.options.files', sortedPaths);
    grunt.task.run(['mochacli:local']);
  });

  grunt.registerTask('test', ['runMochaTests']);
  grunt.registerTask('livetests', [ 'watch:tests']);

};

补充说明

使用上面的配置。 运行ning $ grunt livetests 通过您的 CLI,然后随后保存修改后的测试文件将导致 Mocha 到 运行 每个测试文件按时间顺序排列文件上次修改日期(即最近修改的文件将 运行 放在最前面,最后修改的文件将 运行 最后)。同样的逻辑也适用于运行宁$ grunt test

但是,如果您希望 Mocha 先 运行 最近修改的文件,然后 运行 其他文件按正常顺序排列(即按名称), 那么上面 Gruntfile.js 中的自定义 runMochaTests Task 应该替换成下面的逻辑:

/**
 * Custom task to dynamically configure the `mochacli.options.files` Array.
 * The filepaths that match the given globbing pattern(s), which is specified
 # via the `grunt.file.expand` method, will be in normal sort order (by name).
 * However, the most recently modified file will be repositioned as the first
 * item in the `filePaths` Array (0-index position).
 */
grunt.registerTask('runMochaTests', function configMochaTask() {
  var filePaths = grunt.file.expand({ filter: 'isFile' }, 'tests/**/*.js')
    .map(function(filePath) {
      return filePath
    });

  var latestModifiedFilePath = filePaths.map(function(filePath) {
      return {
        fpath: filePath,
        modtime: statSync(filePath).mtime.getTime()
      }
    })
    .sort(function (a, b) {
      return a.modtime - b.modtime;
    })
    .map(function (info) {
      return info.fpath;
    })
    .reverse()[0];

  filePaths.splice(filePaths.indexOf(latestModifiedFilePath), 1);
  filePaths.unshift(latestModifiedFilePath);

  grunt.config('mochacli.options.files', filePaths);
  grunt.task.run(['mochacli:local']);
});