如何在更新时自动 运行 单个 phpunit 测试?

How to automatically run a single phpunit test when it is updated?

我正在使用 Laravel 5.3,不幸的是,当您 运行 gulp tdd 时,对 1 个文件的更改 运行 整个测试套件现在需要将近 2 分钟。参考,我开始使用G运行t到运行特定文件更改时的特定测试。下面的示例 G运行t 文件:

Gruntfile.js:

var phpunit = 'vendor/bin/phpunit ';
grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    watch: {
        HomeSrc: {
            files: [
                'app/Http/**/HomeController.php',
                'resources/views/home/**/*.php'
            ],
            tasks: ['HomeTests']
        },
    shell: {
        HomeTests: { command: phpunit + 'tests/Home' },
    }
});

但是,现在我的 G运行t 文件变得很长,我想 运行 更改后的特定测试文件。

问题

  1. 有没有更有效的方法来做到这一点? (更好地组织 G运行 文件或改用 Gulp)
  2. 我如何运行 更改文件后进行特定测试?

示例: 当tests/Home/IndexTest.php改变时,自动运行vendor/bin/phpunit tests/Home/IndexTest.php

使用命令行

转到您的项目文件夹,然后在合适的命令下运行

运行 所有测试 class 个文件

phpunit

运行具体测试class文件

phpunit ./tests/ExampleTest.php

运行 来自 class 文件 运行 命令下的特定测试用例

phpunit --filter testBasicExample ./tests/ExampleTest.php

好的,要处理这个问题,您需要捕获匹配的文件名并动态设置一个变量以用作单元测试文件。这应该涵盖所有基本映射,其中测试 class 名称与其所在的文件名完全相同,并且支持名称空间,因此并非所有具有相同 class 名称的测试文件都会被选择过滤器。

示例:

grunt.initConfig({
    // .. snipped ..
    unitTestFile: 'to_be_replaced',
    watch: {
        php: {
            files: ["tests/**/*.php"],
            tasks: ["shell:unitTest"],
            options: {
                spawn: false
            }
        }
    },
    shell: {
        unitTest: {
            command: "phpunit --filter <%= unitTestFile %>"
        }
    }

    grunt.loadNpmTasks('grunt-shell');

    grunt.event.on('watch', function (action, filepath) {
        if (grunt.file.isMatch(grunt.config('watch.php.files'), filepath)) {
            var testFile = filepath.replace(/\/g, '\\');
            grunt.config('unitTestFile', testFile.replace(/.php/, ''));
        }
    });
};

因此,如果更改了名为 tests\unit\ApplicationTest.php 且位于 tests\unit 命名空间内的文件,现在将 运行 作为测试。结果命令为:

phpunit --filter tests\unit\ApplicationTest // only runs in this namespace

您可以考虑以下解决方案:

  1. 利用外部 .json,其中包含您打算观看的 files/paths 数组,最终 运行 作为单元测试。
  2. watchshell 任务动态生成 Targets

(以上两点肯定有助于减少代码行数。)

下面的要点证明了这一点:


JSON

假设我们有一个名为 test-mappings.json 的文件,每个文件路径 (根据第 1 点) 指定如下,并与 [= 一起保存在项目根目录中17=]

[{
    "file": "tests/testA.php"
},{
    "file": "tests/testB.php"
},{
    "file": "tests/testC.php"
},{
    "file": "tests/testD.php"
}]

Gruntfile.js

使用一个Gruntfile.js配置如下:

module.exports = function(grunt) {

    'use strict';

    var mapping = grunt.file.readJSON('test-mappings.json'),
        watch = {},
        shell = {};

    // Dynamically create the targets for 'watch' and 'shell' tasks.
    mapping.forEach(function(config, index) {
        watch[index] = {
            files: [config.file],
            tasks: [index]
        };

        shell[index] = {
            command: 'vendor/bin/phpunit ' + config.file
        };

        // Register the shell target
        grunt.registerTask(index, ['shell:' + index ]);
    });

    grunt.initConfig({
        watch: watch,
        shell: shell
    });

    // Handy for dev - logs generated targets
    //grunt.log.writeln(JSON.stringify(grunt.config(), null, 2));

    require('load-grunt-tasks')(grunt);

    grunt.registerTask('default', [
        'watch'
    ]);
};

请注意,watchshell 任务的每个目标都是根据 test-mappings.json 中指定的文件列表动态生成和配置的。

要查看自动生成目标的配置,您只需在 运行ning $ grunt 之前取消注释 grunt.log.writeln... 行,它将打印到控制台。


运行任务

  1. 通过 CLI 输入 $ grunt
  2. test-mappings.json 中列出的文件之一进行编辑并保存。
  3. watch 任务将 运行 相应的 shell 命令。

补充说明

  1. 目前,文件列在外部 .json 中,但它们可以驻留在 Gruntfile.js 中,如果愿意,可以分配给变量。

  2. 或者,可以使用适当的 globbing pattern(s) and modifying the gist above as necessary. In which case iterating over grunt.file.expand 获取文件,而不是当前的 mapping 数组。

  3. 以下 g运行t 插件用于上述要点:


更新:

下面的Gruntfile.js是针对第1点前面提到的方法。 附加说明 节下的两个(即 Globbing 而不是外部 JSON 文件路径配置)。

module.exports = function(grunt) {

    'use strict';

    var tests = 'tests/**/*.php',
        watch = {},
        shell = {};

    grunt.file.expand(tests).forEach(function(filepath, index) {
        watch[index] = {
            files: [filepath],
            tasks: [index]
        };
        shell[index] = {
            command: 'vendor/bin/phpunit ' + filepath
        };
        grunt.registerTask(index, ['shell:' + index]);
    });

    grunt.initConfig({
        watch: watch,
        shell: shell
    });

    require('load-grunt-tasks')(grunt);

    grunt.registerTask('default', [
        'watch'
    ]);

};