自从我开始使用Gulp,我的项目变得越来越复杂。现在我有一些相当不错的任务,所以我在想也许我应该构建一些单元测试来保持正常吗?
有没有一种好而简单的方法来加载Gulpfile并确保我的任务正在执行我想要它们做的事情?
有人测试过他们的脚本吗,还是这完全是浪费时间?
自从我开始使用Gulp,我的项目变得越来越复杂。现在我有一些相当不错的任务,所以我在想也许我应该构建一些单元测试来保持正常吗?
有没有一种好而简单的方法来加载Gulpfile并确保我的任务正在执行我想要它们做的事情?
有人测试过他们的脚本吗,还是这完全是浪费时间?
我的方法是创建一个测试实例,使用 exec
和 yeoman-assert。虽然感觉更像是集成测试,但我发现这样有助于确保任务正常运行(我的用例是一个yeoman-generator)。一些(mocha)示例如下:
'use strict';
var path = require('path');
var helpers = require('yeoman-generator').test;
var assert = require('yeoman-generator').assert;
var exec = require('child_process').exec;
var fs = require('fs');
var injectStyles = require('../.test-instance/tasks/dev');
describe('gulp inject', function ()
{
var instancePath = path.join(__dirname, '../.test-instance');
var mainScss = path.join(instancePath, 'app/styles/main.scss');
var gulpfile = path.join(instancePath, 'gulpfile.js');
var gulp = '$(which gulp)';
var injectStylesCmd = gulp + ' injectStyles';
describe('scss partials in styles folder', function ()
{
var expectedContent = [
[mainScss, /_variables/],
[mainScss, /base\/_buttons\.scss/],
[mainScss, /base\/_fonts\.scss/],
[mainScss, /base\/_forms\.scss/],
[mainScss, /base\/_icons\.scss/],
[mainScss, /base\/_lists\.scss/],
[mainScss, /base\/_page\.scss/],
[mainScss, /base\/_tables\.scss/],
[mainScss, /base\/_typography\.scss/],
[mainScss, /functions\/_some-function\.scss/],
[mainScss, /mixins\/_some-mixin\.scss/],
[mainScss, /placeholders\/_some-placeholder\.scss/]
];
var expected = [
mainScss
];
beforeEach(function (done)
{
this.timeout(10000);
fs.truncateSync(mainScss);
fs.writeFileSync(mainScss, '// inject:sass\n\n// endinject');
exec(injectStylesCmd + ' injectStyles', {
cwd: instancePath
}, function (err, stdout)
{
done();
});
});
it('creates expected files', function ()
{
assert.file([].concat(
expected
));
assert.fileContent([].concat(
expectedContent
));
});
});
});
当然,你需要确保你已经设置了一个测试实例。你可以通过使用fs.writeFileSync
创建你的测试文件。在大多数情况下,你需要确保该实例具有相同的目录结构,并且至少存在gulpfile。npm install
过程? - teoneexec
语句(它仍然需要使用 promises 进行重构...但是它可以工作)。 - teone最终对我有效的解决方案(主要关注构建过程),不是单独测试gulp任务,而是有源文件目录,将源文件复制到指定位置,运行gulp(作为shell命令的“gulp build”),并将输出目录和文件与包含正确输出的另一个目录进行比较。-
我为我的任务创建了测试,其中有两种类型的测试:
为了确保易于测试,我将从任务到gulp插件的所有内容模块化。
单元测试
集成测试
够聊了,下面是一个使用jasmine混合单元测试和集成测试的示例:
/* spec/lib/tasks/build_spec.js */
var gulp = require("gulp");
var through2 = require("through2");
var exec = require("child_process").exec;
var env = require("../../../lib/env");
var build = require("../../../lib/tasks/build");
var gulpif = require("../../../lib/adapters/gulpif");
var gzip = require("../../../lib/adapters/gzip");
var uglify = require("../../../lib/adapters/uglify");
describe("build", function(){
it("stream to uglify then gzip if environment is production", function(testDone){
var streamSequence = [];
// 1. Stub condition and output path
spyOn(env, "production").and.returnValue(true);
spyOn(build, "dest").and.returnValue("./tmp");
// 2. Stub debug message for stream sequence
spyOn(gulpif, "stream").and.callFake(function(env, stream){
if (env.production()) streamSequence.push(stream.debug["stream-name"]);
return through2.obj();
});
spyOn(uglify, "stream").and.callFake(function(){
var stream = through2.obj();
stream.debug = { "stream-name": "stream-uglify" };
return stream;
});
spyOn(gzip, "stream").and.callFake(function(){
var stream = through2.obj();
stream.debug = { "stream-name": "stream-gzip" };
return stream;
});
var stream = build.run();
var url = "file://" + process.cwd() + "/tmp/resource.js";
stream.on("end", function(){
// 3. Assert stream sequence (unit test)
expect(streamSequence).toEqual(["stream-uglify", "stream-gzip"]);
exec("curl " + url, function(error, stdout, stderr){
// 4. Assert stream output (integration)
expect(eval.bind(Object.create(null), stdout)).not.toThrow();
testDone();
});
});
});
});
以下是任务的模块示例:
/* lib/tasks/build.js */
var gulp = require("gulp");
var env = require("../env");
var gulpif = require("../adapters/gulpif");
var gzip = require("../adapters/gzip");
var uglify = require("../adapters/uglify");
var build = {
dest: function(){
return "./path/to/output";
},
run: function(){
return gulp.src("./path/to/resource.js")
.pipe(gulpif.stream(env.production(), uglify.stream()))
.pipe(gulpif.stream(env.production(), gzip.stream()))
.pipe(gulp.dest(this.dest()));
}
};
module.exports = build;
以下是适配器:
/* lib/adapters/gulpif.js */
var gulpif = require("gulp-if");
var adapter = {
stream: function(){
return gulpif.apply(Object.create(null), arguments);
}
};
module.exports = adapter;
/* lib/adapters/gzip.js */
var gzip = require("gulp-gzip");
var adapter = {
stream: function(){
return gzip.apply(Object.create(null), arguments);
}
};
module.exports = adapter;
/* lib/adapters/uglify.js */
var gzip = require("gulp-uglify");
var adapter = {
stream: function(){
return uglify.apply(Object.create(null), arguments);
}
};
module.exports = adapter;
这里是用于演示条件测试的环境:
/* lib/env.js */
var args = require("yargs").argv;
var env = {
production: function(){
return (args.environment === "production");
}
}
最后,这是一个使用任务模块示例的任务:
/* tasks/build.js */
var gulp = require("gulp");
var build = require("./lib/tasks/build");
gulp.task("build", function(){
build.run();
});
我知道这不是完美的,有一些重复的代码。但我希望这能给你展示我如何测试我的任务。
gulp = require 'gulp'
$ = require('gulp-load-plugins')()
require('./src/build/build-task')(gulp, $)
gulp.task "default", ['build']
在./src/build/build-task.coffee
中:
module.exports = (gulp, $)->
gulp.task "build",->
$.util.log "running build task"