使用 Karma 和 Mocha.js 对多个用例进行单元测试
Unit-testing multiple use cases with Karma & Mocha.js
我对测试还很陌生,所以这个问题是关于最佳实践以及这个测试应该如何编写的。我将 Karma 与 Mocha 和 Chai 一起使用来测试 Angular.js 应用程序。
我目前正在测试一个函数,该函数计算按特定顺序排列字母组合的方式的数量。它遵循一种模式从辅音组或元音组中提取字母。
这些是我目前的测试:
describe("should count the number of combinations correctly", function() {
describe("with 2-item arrays", function() {
beforeEach(function(){
scope.vowels = ['a', 'e'];
scope.consonants = ['b', 'c'];
})
it("with 2 letters in pattern", function() {
scope.pattern = 'CV';
expect(scope.combinationCounter()).to.equal(4);
});
it("with 3 letters in pattern", function() {
scope.pattern = 'CVC';
expect(scope.combinationCounter()).to.equal(8);
});
it("with 4 letters in pattern", function() {
scope.pattern = 'CVCV';
expect(scope.combinationCounter()).to.equal(16);
});
});
describe("with 3-item arrays", function() {
beforeEach(function(){
scope.vowels = ['a', 'e', 'i'];
scope.consonants = ['b', 'c', 'd'];
})
it("with 2 letters in pattern", function() {
scope.pattern = 'CV';
expect(scope.combinationCounter()).to.equal(9);
});
it("with 3 letters in pattern", function() {
scope.pattern = 'CVC';
expect(scope.combinationCounter()).to.equal(27);
});
it("with 4 letters in pattern", function() {
scope.pattern = 'CVCV';
expect(scope.combinationCounter()).to.equal(81);
});
});
});
这些测试有效,它们给了我有用的错误信息,但我不禁觉得我在做一些不必要的重复,因为我实际上是在用不同的值执行相同的测试。
有没有一种方法可以编写这些保持错误消息结构但不需要我写出来的测试
it("with x letters in pattern", function() {
scope.pattern = 'whatever';
expect(scope.combinationCounter()).to.equal(y);
});
每一次?
我想在没有庞大测试文件的情况下测试更多案例,但要保持错误消息可读。
编辑: @Stas 回答的问题
@Stas 给了我正确的答案,就是使用一个带有对象的循环来保存不同的测试用例。但是,由于他的答案是用我没有使用的 lodash 编写的,因此我在下面包含了我的最终循环代码以供参考。
我在此处循环的 scenarios
对象与@Stas 示例中的对象相同。
for (var x in scenarios) {
var vowels = scenarios[x].arrays.vowels;
var consonants = scenarios[x].arrays.consonants;
var v = vowels;
var c = consonants;
describeStuff();
}
function describeStuff(){
describe("with " + x, function(){
setLetters(v,c);
});
}
function setLetters(vowels, consonants){
describe("("+vowels + ' & ' + consonants + "),", function(){
beforeEach(function(){
scope.vowels = vowels;
scope.consonants = consonants;
});
innerLoop();
});
}
function innerLoop(){
for (var y in scenarios[x].combinations) {
var combinations = scenarios[x].combinations;
var pat = scenarios[x].combinations[y].pattern;
var res = scenarios[x].combinations[y].result;
setResults(pat, res);
}
}
function setResults(p, r){
var pattern = p;
var result = r;
it("with " + p.length + " letters in pattern (" + p + ")", function(){
scope.pattern = pattern;
expect(scope.combinationCounter()).to.equal(result);
});
}
我不得不使用四个相互调用的函数链来编写循环,因为在 for in
循环中使用 Mocha 的回调语法只会导致最终测试用例保存到函数变量中。在循环外定义函数然后在循环内调用它们可以解决此问题。
您可以创建场景对象并为每个循环包装执行(在此示例中我使用的是 lodash):
describe("should count the number of combinations correctly", function () {
var scenarios = {
"2-item arrays": {
arrays: {
vowels: ['a', 'e'],
consonants: ['b', 'c']
},
combinations: [
{pattern: "CV", result: 4},
{pattern: "CVC", result: 8},
{pattern: "CVCV", result: 16}
]
},
"3-item arrays": {
arrays: {
vowels: ['a', 'e', 'i'],
consonants: ['b', 'c', 'd']
},
combinations: [
{pattern: "CV", result: 9},
{pattern: "CVC", result: 27},
{pattern: "CVCV", result: 81}
]
}
};
_.forEach(scenarios, function (scenario, key) {
describe("with " + scenario.key, function () {
beforeEach(function () {
scope.vowels = scenario.arrays.vowels;
scope.consonants = scenario.arrays.consonants;
});
_.forEach(scenario.combinations, function(combination) {
it("with " + combination.pattern.length + " letters in pattern", function() {
scope.pattern = combination.pattern;
expect(scope.combinationCounter()).to.equal(combination.result);
});
})
});
});
});
这样您就可以添加更多场景而无需为每个组合重复 describe() / beforeEach() / it() 并且它会产生相同的消息。
我对测试还很陌生,所以这个问题是关于最佳实践以及这个测试应该如何编写的。我将 Karma 与 Mocha 和 Chai 一起使用来测试 Angular.js 应用程序。
我目前正在测试一个函数,该函数计算按特定顺序排列字母组合的方式的数量。它遵循一种模式从辅音组或元音组中提取字母。
这些是我目前的测试:
describe("should count the number of combinations correctly", function() {
describe("with 2-item arrays", function() {
beforeEach(function(){
scope.vowels = ['a', 'e'];
scope.consonants = ['b', 'c'];
})
it("with 2 letters in pattern", function() {
scope.pattern = 'CV';
expect(scope.combinationCounter()).to.equal(4);
});
it("with 3 letters in pattern", function() {
scope.pattern = 'CVC';
expect(scope.combinationCounter()).to.equal(8);
});
it("with 4 letters in pattern", function() {
scope.pattern = 'CVCV';
expect(scope.combinationCounter()).to.equal(16);
});
});
describe("with 3-item arrays", function() {
beforeEach(function(){
scope.vowels = ['a', 'e', 'i'];
scope.consonants = ['b', 'c', 'd'];
})
it("with 2 letters in pattern", function() {
scope.pattern = 'CV';
expect(scope.combinationCounter()).to.equal(9);
});
it("with 3 letters in pattern", function() {
scope.pattern = 'CVC';
expect(scope.combinationCounter()).to.equal(27);
});
it("with 4 letters in pattern", function() {
scope.pattern = 'CVCV';
expect(scope.combinationCounter()).to.equal(81);
});
});
});
这些测试有效,它们给了我有用的错误信息,但我不禁觉得我在做一些不必要的重复,因为我实际上是在用不同的值执行相同的测试。
有没有一种方法可以编写这些保持错误消息结构但不需要我写出来的测试
it("with x letters in pattern", function() {
scope.pattern = 'whatever';
expect(scope.combinationCounter()).to.equal(y);
});
每一次?
我想在没有庞大测试文件的情况下测试更多案例,但要保持错误消息可读。
编辑: @Stas 回答的问题
@Stas 给了我正确的答案,就是使用一个带有对象的循环来保存不同的测试用例。但是,由于他的答案是用我没有使用的 lodash 编写的,因此我在下面包含了我的最终循环代码以供参考。
我在此处循环的 scenarios
对象与@Stas 示例中的对象相同。
for (var x in scenarios) {
var vowels = scenarios[x].arrays.vowels;
var consonants = scenarios[x].arrays.consonants;
var v = vowels;
var c = consonants;
describeStuff();
}
function describeStuff(){
describe("with " + x, function(){
setLetters(v,c);
});
}
function setLetters(vowels, consonants){
describe("("+vowels + ' & ' + consonants + "),", function(){
beforeEach(function(){
scope.vowels = vowels;
scope.consonants = consonants;
});
innerLoop();
});
}
function innerLoop(){
for (var y in scenarios[x].combinations) {
var combinations = scenarios[x].combinations;
var pat = scenarios[x].combinations[y].pattern;
var res = scenarios[x].combinations[y].result;
setResults(pat, res);
}
}
function setResults(p, r){
var pattern = p;
var result = r;
it("with " + p.length + " letters in pattern (" + p + ")", function(){
scope.pattern = pattern;
expect(scope.combinationCounter()).to.equal(result);
});
}
我不得不使用四个相互调用的函数链来编写循环,因为在 for in
循环中使用 Mocha 的回调语法只会导致最终测试用例保存到函数变量中。在循环外定义函数然后在循环内调用它们可以解决此问题。
您可以创建场景对象并为每个循环包装执行(在此示例中我使用的是 lodash):
describe("should count the number of combinations correctly", function () {
var scenarios = {
"2-item arrays": {
arrays: {
vowels: ['a', 'e'],
consonants: ['b', 'c']
},
combinations: [
{pattern: "CV", result: 4},
{pattern: "CVC", result: 8},
{pattern: "CVCV", result: 16}
]
},
"3-item arrays": {
arrays: {
vowels: ['a', 'e', 'i'],
consonants: ['b', 'c', 'd']
},
combinations: [
{pattern: "CV", result: 9},
{pattern: "CVC", result: 27},
{pattern: "CVCV", result: 81}
]
}
};
_.forEach(scenarios, function (scenario, key) {
describe("with " + scenario.key, function () {
beforeEach(function () {
scope.vowels = scenario.arrays.vowels;
scope.consonants = scenario.arrays.consonants;
});
_.forEach(scenario.combinations, function(combination) {
it("with " + combination.pattern.length + " letters in pattern", function() {
scope.pattern = combination.pattern;
expect(scope.combinationCounter()).to.equal(combination.result);
});
})
});
});
});
这样您就可以添加更多场景而无需为每个组合重复 describe() / beforeEach() / it() 并且它会产生相同的消息。