设计模块的最佳方法,以便轻松模拟和测试其状态

时间:2015-05-25 08:13:56

标签: javascript requirejs

我有两个需要的模块:

state.js

define(function () {
    var stateObj = {hello:"test!"};

    return {
        getObj: function () {  
            return stateObj; 
        }
    };
});

main.js

define(['state'],function (global) {
    var privateFn = global.getObj()

    return {
        getHello: function () {
            if(privateFn.hello == "test!")
               //do someoperation
        },
        changeState : function() {
             //changes the privateFn state
        }
    };
});

state模块将对象提供给main模块,用于内部状态存储。为main内部状态保留单独模块的原因是为了便于测试,因此在我的测试用例中,我可以注入一个假state模块并检查main的方式}模块工作。

由于我是js world的新手,我在这里采取的方法是否正确,我不确定。

1 个答案:

答案 0 :(得分:1)

如果你有一个downvote,那么可能是因为很难以一种明确的方式回答。事实上,我正在查看代码,甚至不确定你在问什么。以下是我的一些想法,但要注意其他人可能非常不同意。

你的州是一个单身人士,所以应该很容易测试。假设您上面的changeState方法如下所示:

changeState: function (key, value) {
    privateFn[key] = value;
}

然后,您可以通过同时包含statemain对其进行测试,然后调用main.changeState并查看state是否按预期更新:

main.changeState('foo', 'bar');
expect(state.foo).toBe('bar');

执行此操作的其他方法(如果state不是单例),实际上是在main上公开状态。这通常通过在前缀下加下划线来完成,因此它被认为是私有的(命名约定,它实际上不是私有的)。然后,在您的测试中,您可以“欺骗”并直接查看状态。

main.changeState('foo', 'bar');
expect(main._state.foo).toBe('bar');

另一种方式是通过依赖注入(这在角度世界中很流行)。这意味着main需要是某种类型的工厂或类。如果你来自一个java世界,那么一个类可能最有意义:

// Some other file where both main.js and state.js is imported
var main = new Main({
    state: state
});

因此main.js不会自行导入任何内容。

我希望这能回答你的问题。

虽然我正在打字(打字):小心你的命名。 global通常是指windowroot也是如此),因此让global提及您的州是非常令人困惑的。赋予它相同的名称:state。此外,您的privateFn指的是一个对象,而不是一个函数(正如Fn后缀所暗示的那样)。也令人困惑。

我不确定每个人都会同意我的第三件事是“国家”应该指的是国家本身。它在这里是一个包装器。有点像BackboneJS的Model(其中attributes就是我所说的state)。区分这两者很重要:

  1. 包装器,揭示有用的方法和其他东西
  2. 和实际数据(通常是对象)。
  3. 实际数据通常(如果不是总是)可以转换为JSON并发送存储在服务器上。与Java不同(我认为?),您的状态应该始终容易与其类/包装器分离。包装器可以(应该)依赖于数据,但数据绝对不应该依赖于它的包装器。

    修改

    我刚刚意识到,也许你的意思是main.js是数据的包装器(也是唯一的包装器)。如果是这种情况,那么我将以不同的方式构建它。我只有一个文件。类似的东西:

    function modelFactory (options) {
        var state = options.state || {};
    
        // Useful methods...
        return {
            get: function (key) {
                return state[key];
            },
            set: function (key, value) {
                state[key] = value;
                // Maybe trigger some change event for others to listen for
            },
            toJSON: function () {
                return JSON.stringify(state);
            }
            // ...
        }
    }
    

    然后测试它,你可以做到

    var model = modelFactory({
        state: {foo: 'bar'}
    });
    
    expect(model.get('foo')).toBe('bar');
    
    model.set('hello', 'world');
    expect(model.get('hello')).toBe('world');
    

    我上面描述的是Backbone.Model

    的基础知识