测试流星 - 使用单元测试而不是集成测试来测试允许/拒绝

Testing meteor - testing allow / deny with a unit test instead of integration test

我有一个应用程序代码以下列方式限制文档

Docs.allow({
  insert: function(userId, doc){
    return !!userId
  },
  update: function(userId, doc){
    return userId && doc.owner == userId;
  }
})

目前,我只能运行 进行实际 http 调用的集成测试。我无法在被测系统外部存根组件(Meteor 当前用户)(允许/拒绝规则)。

it("should succeed if user is authenticated", function(done) {
    Meteor.loginWithPassword(’shawn@abc.com', ‘hahaha', function(err){
        expect(err).toBe(undefined);
        Doc = Docs.insert({title: 'abc', 
                           category: 'Finance'}, 
                          function(err, id){
                              expect(err).toBeUndefined();
                              expect(id).not.toBeUndefined();
                              done();
                          });
    });
});

it("should fail if user is not authenticated", function(done) {
    Meteor.logout(function(){
        doc = Docs.insert({title: 'abc', 
                           category: 'Finance', 
                           owner: '1232131'}, 
                          function(err, id){
                              expect(err).not.toBeUndefined();
                              done();
                          });
    });
});

这使我的测试非常慢,尤其是当我要测试很多路径时。有没有办法让我将此测试移至较低级别的单元测试?

此测试在服务器代码上练习执行路径,这是 allow/deny 规则所在的位置。

这里的测试没有做client-server的集成,你的client集成测试做的很好

您可以使用单元测试覆盖代码中的所有执行路径,然后减少集成测试,从而获得您想要的速度。

你应该尽可能多的进入下层,但不要面面俱到。您仍然想确保集成也有效。

describe('Doc security rules', function () {

  var _oldAllowRules;

  beforeAll(function () {
    var _allowRules = null;

    // keep hold of the old Docs.allow method so we can restore in the after step
    _oldAllowRules = Docs.allow;

    // override the Docs.allow method so we can isolate the allow rules code
    Docs.allow = function (allowRules) {
      _allowRules = allowRules;
    };
  });

  afterAll(function () {
    // restore the Docs.allow method 
    Docs.allow = _oldAllowRules;
  });

  it('insert deny access to non-logged in users', function () {
    // Execute
    // you can now exercise the allowRules directly 
    var response = _allowRules.insert(null, {});

    // Verify
    expect(response).toBe(false);
  });

  it('update allows for doc owner', function () {
    // you can do it all with one step
    expect(_allowRules.update(1234, {owner: 1234})).toBe(true);
  });

  it('update denies for logged out user', function () {
    expect(_allowRules.update(null, {})).toBe(false);
  });

  it('update denies for non document owner', function () {
    expect(_allowRules.update(1234, {owner: 5678})).toBe(false);
  });

});

基于 Meteor 测试手册的答案...Stories.allow 模拟是在应用程序代码加载后定义的。因此,它没有效果。

https://github.com/Sanjo/meteor-jasmine#stubs

中所述

Files in tests/jasmine folder (or a subfolder of it) that end with -stubs.js or -stub.js are treated as stubs and are loaded before the app code.

所以为了使流星测试手册的答案有效,我们必须在 -stubs.js 文件中定义存根/模拟。这就是我在 z-security-stubs.js.

上所做的

注意我在文件名前加了'z'前缀,因为meteor加载的文件在同级子目录中是按字母顺序排列的。我们必须确保我们自定义的存根在 Velocity 自动生成的 package-stubs.jspackageMocksSpec.js 之后加载。

考虑到这一点,z-security-stubs.js 可以包含如下内容:

Mongo.Collection.prototype.allow = function(rules){
  this._velocityAllow = rules;
}

Mongo.Collection.prototype.deny = function(rules){
  this._velocityDeny = rules;
}

这在集合实例的 属性 中保留了对我们的允许/拒绝安全规则的引用(例如,文档、文件或您的集合的任何名称);

之后我们可以参考这个属性中的安全函数,进行断言:

describe("Docs security rules", function() {
  var allow;

  beforeEach(function(){
    allow = Docs._velocityAllow;
  });

  it("insert deny access to non-logged in users", function() {
    var response = allow.insert(null, {});
    expect(response).toBe(false);
  });

  it("insert allow access to logged in users", function() {
    var response = allow.insert(true, {});
    expect(response).toBe(true);
  });

  it("update allow access to logged in users who are owners", function() {
    var response = allow.insert(2, {owner: 2});
    expect(response).toBe(true);
  });

  it("update deny access to non-logged in users", function() {
    var response = allow.update(null, {owner: 2});
    expect(response).toBe(false);
  });

  it("update deny access to logged in users who are not owners", function() {
    var response = allow.update(1, {owner: 2});
    expect(response).toBe(false);
  });
});