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

我与影子孤独终老i 提交于 2019-12-12 04:34:32

问题


I am using Laravel 5.3 and unfortunately when you run gulp tdd, a change to 1 file runs the entire test suite which now takes nearly 2 minutes. With reference to this post, I started using Grunt to run specific tests when specific files are changed. Sample Gruntfile below:

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' },
    }
});

However, now my Gruntfile is getting pretty long and I would like to run specific test files when they are changed.

Questions

  1. Is there a more efficient way to do this? (better organization of the Grunfile or using Gulp instead)
  2. How can I run a specific test when its file is changed?

Example: When tests/Home/IndexTest.php is changed, automatically run vendor/bin/phpunit tests/Home/IndexTest.php


回答1:


OK, to handle this you will need to catch the matched file name and dynamically set a variable to use as the unit test file. This should cover all basic mappings where the test class name is exactly the same name as the file name it is within, and supports namespaces so not all test files with the same class name will be picked up by the filter.

Example:

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/, ''));
        }
    });
};

So, a file named tests\unit\ApplicationTest.php and within a namespace of tests\unit if changed will now run that as a test. The resulting command being:

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



回答2:


Using command line

go to your project folder then run below suitable command

Run all test class files

phpunit

Run specific test class file

phpunit ./tests/ExampleTest.php

or

Run specific test case from class file run below command

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




回答3:


You could consider the following solution:

  1. Utilize an external .json which includes an array of files/paths you intend to watch and ultimately run as a unit test.
  2. Dynamically generate the Targets for both the watch and shell Tasks.

(Both points above will certainly help to reduce the lines of code.)

The following gist demonstrates this:


JSON

Lets assume we have a file named test-mappings.json with each file path (as per point 1) specified as followed and saved in the projects root directory alongside Gruntfile.js

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

Gruntfile.js

Use a Gruntfile.js configured as follows:

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'
    ]);
};

Notice each Target for both the watch and shell Tasks are dynamically generated, and configured, according to the file list specified in test-mappings.json.

To see the configuration of the auto generated targets you can simply uncomment the line reading grunt.log.writeln..., before running $ grunt, and it will be printed to the console.


Running the task

  1. Type $ grunt via the CLI.
  2. Make an edit to one of the files listed in test-mappings.json and save it.
  3. The watch task will then run the corresponding shell command.

Additional notes

  1. Currently the files are listed in an external .json, however they could reside in the Gruntfile.js and be assigned to a variable if preferred.

  2. Or, the files could be obtained using the appropriate globbing pattern(s) and modifying the gist above as necessary. In which case iterating over grunt.file.expand will be handy for that, instead of the current mapping array.

  3. The following grunt plugins were used for the above gist:

    • grunt-contrib-watch

    • grunt-shell

    • load-grunt-tasks


Update:

The following Gruntfile.js is for the approach previously mentioned in point no. two under the Additional notes secton (i.e. Globbing instead of an external JSON filepath config).

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

};


来源:https://stackoverflow.com/questions/41730127/how-to-automatically-run-a-single-phpunit-test-when-it-is-updated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!