1

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

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

这使我的测试变得异常缓慢,尤其是在我想测试许多路径的情况下。有没有办法让我将此测试移至较低级别的单元测试?

4

2 回答 2

4

建立在 The Meteor Test Manual 的答案之上……Stories.allow模拟是在应用程序代码加载后定义的。因此,它没有任何作用。

https://github.com/Sanjo/meteor-jasmine#stubs中所述,

tests/jasmine 文件夹(或其子文件夹)中以 -stubs.js 或 -stub.js 结尾的文件被视为存根,并在应用程序代码之前加载。

因此,要使 The Meteor Test Manual 的答案起作用,我们必须在 -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;
}

这会在集合实例的属性中保留对我们允许/拒绝安全规则的引用(例如,Docs、Files 或您的集合命名的任何内容);

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

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);
  });
});
于 2015-02-07T05:29:00.323 回答
0

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

这里的测试没有执行客户端和服务器之间的集成,这就是你的客户端集成测试做得很好。

您可以使用单元测试来覆盖代码中的所有执行路径,然后减少集成测试,因此您将获得所需的速度。

你应该尽可能多地进入较低的层次,但不是一切。您仍然希望确保集成也有效。

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

});
于 2015-02-04T01:31:48.730 回答