【问题标题】:How can I test a Backbone subclass in Mocha without duplicating tests for the superclass?如何在 Mocha 中测试 Backbone 子类而不重复对超类的测试?
【发布时间】:2015-05-11 19:10:58
【问题描述】:

假设我有几个 Backbone 模型,矩形和三角形,每个都扩展多边形。

var Polygon = Backbone.Model.extend({
    defaults: {
       width: 100,
       height: 100,
       rotation: 0
    },
    rotate: function (degrees) {
       var oldRotation = this.get('rotation');
       var newRotation = (oldRotation + degrees) % 360;
       this.set('rotation', newRotation);
       return newRotation;
    }
});

var Rectangle = Polygon.extend({
    area: function (degrees) {
      return this.get('width') * this.get('height');
    }
});

var Triangle = Polygon.extend({
    area: function (degrees) {
      return this.get('width') * this.get('height') / 2;
    }
}

我想测试 Rectangle 和 Triangle 并确保它们各自正确地独立实现 rotate,尽管我知道(目前)它们都从 Polygon 继承了 rotate 的实现。

我不想做的是为 Rectangle 和 Triangle 创建单独的单元测试,它们几乎是彼此完全相同的副本。在 Mocha 中,如何为 rotate 编写测试并在三角形和矩形的单元测试中重用它?

这是我的单元测试。请注意重复的“旋转 45 度”测试。

describe('A rectangle', function () {
  var r = new Rectangle({width: 50, height: 10, rotation: 90});
  it('correctly calculates its area', function () {
    expect(r.area()).to.equal(500);
  });
  it('rotates by 45 degrees', function () {
    expect(r.rotate(45)).to.equal(135);
  });
});

describe('A triangle', function () {
  var t = new Triangle({width: 50, height: 10, rotation: 90});
  it('correctly calculates its area', function () {
    expect(t.area()).to.equal(250);
  });
  it('rotates by 45 degrees', function () {
    expect(t.rotate(45)).to.equal(135);
  });
});

【问题讨论】:

  • rotate()在子类中没有变化,为什么还要重新测试?您可以将rotate() 测试限制为Polygon 的测试。
  • 这个想法是多边形具有某些不变量,无论正在测试多边形的哪个子类,测试都应该始终通过。未来,Triangle 可能会实现rotate() 方法来添加一些功能。我想确保Polygon.rotate() 的不变量仍然满足Triangle.rotate()

标签: javascript unit-testing oop backbone.js mocha.js


【解决方案1】:

写出来答案就很明显了。我们可以创建一个函数来封装多边形的测试。

var describeAPolygon = function (name, p) {
    describe(name, function () {        
      it('rotates by 45 degrees', function () {
        expect(p.rotate(45)).to.equal(135);
      });
    });
};

然后在矩形和三角形的测试中使用它。

describe('A rectangle', function () {
    var r = new Rectangle({width: 50, height: 10, rotation: 90});
    describeAPolygon('A rectangle', r);
    it('correctly calculates its area', function () {
      expect(r.area()).to.equal(500);
    });
});


describe('A triangle', function () {
    var t = new Triangle({width: 50, height: 10, rotation: 90});
    describeAPolygon('A triangle', t);
    it('correctly calculates its area', function () {
      expect(t.area()).to.equal(250);
    });
});

这是我能找到的最干净的解决方案。我很好奇是否有其他人解决了这个问题并提出了不同的建议。

【讨论】:

    【解决方案2】:

    我通常做的是:

    describe('A rectangle', function () {
        var r = new Rectangle({width: 50, height: 10, rotation: 90});
    
        it('should be a polygon', function() {
          expect(r).to.be.an.instanceof(Polygon);
        });
    
        it('correctly calculates its area', function () {
          expect(r.area()).to.equal(500);
        });
    });
    
    describe('A triangle', function () {
        var t = new Triangle({width: 50, height: 10, rotation: 90});               
    
        it('should be a polygon', function() {
          expect(r).to.be.an.instanceof(Polygon);
        });
    
        it('correctly calculates its area', function () {
          expect(t.area()).to.equal(250);
        });
    });
    
    describe('A polygon', function() { 
        var p = new Polygon({width: 50, height: 10, rotation: 90});
        it('rotates by 45 degrees', function () {
          expect(p.rotate(45)).to.equal(135);
        });
    });
    

    如果您使用正确的 OOP 实践,您的 Polygon 类应该具有足够安全的方法和结构,以确保任何扩展它的类都不能修改它。

    【讨论】:

    • 谢谢。现在让我们假设我们添加另一个方法 cutInHalf(),它返回两个新的多边形。 Triangle 和 Rectangle 将分别以不同的方式实现 cutInHalf()。但我仍然想测试两个生成的多边形的面积加起来是否等于原始多边形的面积,无论哪种类型的多边形被分割。
    • 好吧,在这种情况下,如果ab 是分割多边形而c 是原始多边形,那么重复您的expect(a.area() + b.area()).to.equal(c.area()); 并没有错。看看 ThreeJS 是如何测试它的。 github.com/mrdoob/three.js/blob/master/test/unit/math/… 恕我直言,测试应该是 1. 可读,2. 快速,但如果您不是这种情况,您可以使用您的方法减少代码重复。
    猜你喜欢
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 2015-07-16
    • 2019-01-23
    • 1970-01-01
    • 2013-12-18
    相关资源
    最近更新 更多