当前位置: 首页 > 工具软件 > SinonJS > 使用案例 >

js单元测试sinonjs库

柴砚文
2023-12-01

http://shaynegui.com/javascript-unit-test-sinonjs/

单元测试的意义

  • 提高测试效率
  • 提升代码质量
  • 能够及时重构代码,减少依赖项
  • 更好的理解需求和业务逻辑,因为每一个测试可能对应一个测试用例
  • 好的测试代码可读性强,新人也能很好的通过测试代码了解到需求,减少维护成本

sinonjs就是这样一套面向js的单元测试辅助库

当我们需要测试的某个方法中,需要去某个接口发送http请求获得数据,如果你真实的发送某个请求,那么当有一天你请求的这个服务器挂掉的时候,你的单元测试就怎么也跑不过了,其实我们要测试的时候我们这个方法针对数据库的其他处理逻辑,我们并不是真的关心这个接口是否存在(甚至是否实现),那我们需要模拟一个这样的接口来返回假的数据,sinonjs就是为了解决这个问题的

{
    setUp: function () {
        sinon.spy(jQuery, "ajax");
    },

    tearDown: function () {
        jQuery.ajax.restore(); // Unwraps the spy
    },

    "test should inspect jQuery.getJSON's usage of jQuery.ajax": function () {
        jQuery.getJSON("/some/resource");

        assert(jQuery.ajax.calledOnce);
        assertEquals("/some/resource", jQuery.ajax.getCall(0).args[0].url);
        assertEquals("json", jQuery.ajax.getCall(0).args[0].dataType);
    }
}

以上代码就是模拟了ajax请求,而不会真正的发送一个xmlhttprequest出去,我们只是模拟了它返回的数据和一些行为,方便我们测试其他的逻辑

stub的用法

stub就像一个方法的存根或者树桩,我们可以预设定一些行为给它,然后进行测试

"test should stub method differently based on arguments": function () {  
    var callback = sinon.stub();//创建一个stub对象
    callback.withArgs(42).returns(1);//当调用参数为42的时候返回1
    callback.withArgs(1).throws("TypeError");//当调用参数为1的时候抛出一个异常

    callback(); // No return value, no exception
    callback(42); // Returns 1
    callback(1); // Throws TypeError
    //预先设定了这些行为,我们就可以来测试我们代码的其他逻辑
}

stub的api的一些使用场景

  • withArgs().returns()一般用来使用在同步的代码中
  • callsArgWith用来测试你需要测试的某个方法拥有一个或者多个回调,callsArgWith的第一个参数表示你要模拟第一个回调,它是个索引值,后面的参数就是你要测试回调的参数
sinon.stub(jQuery, "each").callsArgWith(1, {}).returns({});  
//我们要测试$.each方法,它的参数中第0索引参数表示集合,第1个索引参数是一个回调函数,当它被调用的时候,会以callsArgWith方法的第二参数作为参数,并且返回一个空对象
  • yieldsTo一般用在你的测试函数的参数是一个对象,这个对象有很多属性,其中你要测试某一个属性,而刚好这个属性是一个函数
"test should fake successful ajax request": function () {  
    sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]);
    //要模拟success函数,同时传入一个数组给success函数当作参数
    jQuery.ajax({
        success: function (data) {
            assertEquals([1, 2, 3], data);
        }
    });
}

更多用法请参考sinojs的文档

mock的用法

mock更侧重与是测试代码是否作出了行为,Mock对象就像是stubs和spies的组合,并且内建了预编码地验证行为,也被成为期望。Mocks会在前期设置它们的期望(而不会像我们常见的断言一样在执行后判断是否符合期望)并且在接收到不被期望的调用时立即失败。最终mock.verify()的调用会验证所有的期望是否符合

"test should call event handler": function () {  
  var mock = sinon.mock();
  var myElement = document.getElementsByTagName("a")[0];

  dom.addEventListener(myElement, "mouseover", mock);
  dom.fireEvent(myElement, "mouseover");

  mock.verify();
}

如果mock被调用了超过一次,这个测试会立马失败。当verify()被调用时,如果mock没有被调用过则会抛出一个exception

也可以为一个对象上的方法创建mock,这就和spies和stubs一样。接口稍微有些不同,我们需要创建:一个mock对象和设置我们想要给于期望的方法

var mock = sinon.mock(jQuery);  
mock.expects("each").once().callsArgWith(1, {}).returns({});  
//代码创建了jQuery.each方法的期望:只被调用一次,并且指示它向之前的stub一样运作

mock的期望

Sinon的mocks支持了spy和stub的接口,尽管spy的接口比起mocks的接口来说没那么有趣。通常前期你会使用如下的方法来设置期望。注意这些方法也会返回expectation,这样你可以使用链式调用,符合声明使得代码可读性更高

  • execptation.atLeast(callCount) 确保mock的被调用次数达到指定的次数
  • expectation.atMost(callCount)确保mock的被调用次数不会超过指定的次数
  • expectation.exactly(callCount)指定mock被调用的次数。
  • expectation.never()exactly(0)的快捷方法。
  • expectation.once()exactly(1)的快捷方法。
  • expectation.twice()exactly(2)的快捷方法。
  • expectation.thrice()exactly(3)的快捷方法。
  • expectation.withArgs(arg1, arg2, ...)就像spy的calledWith(arg1, arg2, ...)方法一样,只不过是它是用作前期对期望的设置。
  • expectation.withExactArgs(arg1, arg2, ...)就像spy的calledWithExactly(arg1, arg2, ...)方法一样,只不过是它是用作前期对期望的设置。
  • expectation.on(thisObj)期望this值匹配指定的对象

restore方法可以用来还原stub和mock的默认行为,即让测试方法变成原来该做的事情


 类似资料: