简体   繁体   English

使用Karma&Mocha.js对多个用例进行单元测试

[英]Unit-testing multiple use cases with Karma & Mocha.js

I'm fairly new to testing, so this question is about best-practices and how this test ought to be written. 我对测试很新,所以这个问题是关于最佳实践以及应该如何编写这个测试。 I'm using Karma with Mocha and Chai to test an Angular.js app. 我正在使用Karma与Mocha和Chai来测试Angular.js应用程序。

I'm currently testing a function that counts the number of ways to arrange a combination of letters in a specific order. 我目前正在测试一个函数,该函数计算按特定顺序排列字母组合的方式数。 It follows a pattern to pull letters from either the set of consonants or the set of vowels. 它遵循从一组辅音或一组元音中提取字母的模式。

These are my current tests: 这些是我目前的测试:

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

These tests work, and they give me useful error messages, but I can't help feeling like I'm doing some unnecessary repetition, since I'm essentially performing the same tests with different values. 这些测试工作,它们给了我有用的错误信息,但我不禁感觉我正在做一些不必要的重复,因为我基本上用不同的值执行相同的测试。

Is there a way to write these tests that maintains the error message structure, but doesn't require me to write out 有没有办法编写这些维护错误消息结构的测试,但不要求我写出来

it("with x letters in pattern", function() {
  scope.pattern = 'whatever';
  expect(scope.combinationCounter()).to.equal(y);
});  

every single time? 每一次?

I'd like to test a larger numbers of cases without a huge test file, but keep the error messages readable. 我想在没有庞大测试文件的情况下测试大量案例,但要保持错误消息的可读性。

Edit: question answered by @Stas 编辑: @Stas回答的问题

@Stas gave me the right answer, which is to use a loop with an object to hold the different test cases. @Stas给了我正确的答案,即使用带有对象的循环来保存不同的测试用例。 However, since his answer was written with lodash, which I was not using, I've included my final loop code below for reference. 但是,由于他的答案是用lodash编写的,我没有使用,我在下面加入了我的最终循环代码以供参考。

The scenarios object I am looping over here is identical to the one in @Stas' example. 我在这里循环的scenarios对象与@Stas'示例中的scenarios对象相同。

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

I had to write the loop using a chain of four functions that call each other, because using Mocha's callback syntax inside the for in loop causes only the final test cases to be saved to the function variables. 我不得不使用四个相互调用的函数链来编写循环,因为在for in循环中使用Mocha的回调语法只会将最终的测试用例保存到函数变量中。 Defining the functions outside the loop and then calling them inside resolves this issue. 定义循环外部的函数然后在内部调用它们可以解决此问题。

You can create scenario objects and wrap the execution in for each loop (I'm using lodash in this example): 您可以创建场景对象并为每个循环包装执行(我在此示例中使用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);
                });
            })
        });
    });
});

This way you can add more scenarios without duplicating describe() / beforeEach() / it() for each combination and it will produce the same messages. 这样,您可以添加更多场景,而无需为每个组合复制describe()/ beforeEach()/ it(),它将生成相同的消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM