使用Sinon测试Javascript中的私有成员

16
我开始编写一些JavaScript测试,并试图找出检查模块构造函数的私有成员的最佳方法。例如,在下面的示例中,我使用揭示模块模式将公共API公开给我的模块。我想测试在$.getJSON ajax请求的回调期间是否正确设置了privateVar
第二个测试it('should update privateVar', ...)不起作用,因为myModule.privateVar(有意)不在模块的公共API中。
因此,我的问题是,有什么最好的方法可以测试这种行为而无需使privateVar成为公共API的一部分?是否有更好的方法来为测试编写代码,或者可能使用类似SinonJs的东西来监视私有成员?
define('myModule',
    ['jquery'],
    function ($) {
        var
            myVar = "something",
            privateVar = "something else",

            doSomething = function() {
                return $.getJSON('http://myapi.com/do-something', { requestData : "some data" }, function(response){
                    myVar = response.data.value1;
                    privateVar = response.data.value2;
                });
            };

        return {
            doSomething : doSomething,
            myVar : myVar
        };
    }
);

define('test/test.myModule',
    ['myModule', 'chai', 'sinon', 'mocha'],
    function (myModule, chai, sinon) {

        describe("myModule", function() {
            var expect = chai.expect;

            describe('doSomething', function() {

                var value1 = 'value1 value',
                    value2 = 'value2 value';

                beforeEach(function() {
                    sinon.stub($, 'ajax').yieldsTo('success', {
                        data : { value1 : value1, value2 : value2 }
                    });
                });

                afterEach(function() {
                    $.ajax.restore();
                });

                it('should update myVar', function(done) {
                    myModule.doSomething();
                    expect(myModule.myVar).to.equal(value1);
                    done();
                });

                it('should update privateVar', function(done) {
                    myModule.doSomething();
                    expect(myModule.privateVar).to.equal(value2);
                    done();
                });
            });


        });

    }
);

这应该会为测试私有成员的主题提供一些启示:https://dev59.com/9HVD5IYBdhLWcg3wDXF3 - Aditya Manohar
@AdityaManohar 感谢提供链接。在我的情况下,我正在测试一个公共方法,但我想确保它正确地设置了一个非公共属性。 - Robbie
4个回答

6
很不幸,你在这里谈论的内容需要进行集成测试。你希望测试一个变量是否作为外部操作的结果被设置。你应该相信外部方法会在测试中按照你用 sinon 做的那样通过存根(stub)正常工作,从而解决了外部调用的问题。
你需要做的是控制测试条件(比如未经身份验证和已经身份验证),然后测试函数在该情况下的结果。通常我不测试私有成员,但我确实测试从已知的好和坏值中得出的期望行为。
我也读过这篇文章,讨论了私有变量的使用。

这并不是一个真正的集成测试,因为正如你所指出的那样,我已经对ajax调用进行了存根处理以隔离SUT,因此“外部操作”的结果并没有被测试,而是测试了生成逻辑的行为。 - Robbie

3
你唯一能够以这种方式访问私有变量的方法是添加一个公共getter,在测试中稍后调用以验证状态:
在你的类中:

getPrivateVar : function(){ return privateVar; }

然后添加返回语句:

return { getPrivateVar : getPrivateVar, };


2
感谢@rochal,是的,这样做可以实现,但是如果我的privateVar是一些机密信息,比如我不想暴露的auth token,那么添加一个getter方法就等同于将该变量放在公共API中。说实话,我不确定这是否是一个有效的问题。 - Robbie
2
不,你不应该修改你的代码来通过测试。私有方法之所以是私有的,是有原因的。 - Stéphane Bruckert

0

实际上为什么要测试私有变量?这是不可能的/困难的。 那个变量的目的是什么?如果它将作为参数传递给函数,您当然可以通过监视函数是否使用分配给私有变量的特定值来测试函数。


0

你可以使用 rewire

let revertBack = renderCtrl.__set__(privateMember,substituteMember);

要恢复到之前的状态,只需调用revertBack()函数; 更多细节请参见https://www.npmjs.com/package/rewire


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接