gpt4 book ai didi

javascript - 诗农 stub 未被调用

转载 作者:行者123 更新时间:2023-12-03 10:23:13 25 4
gpt4 key购买 nike

在为 baz.View.likeButton 编写测试时,我遇到了这样的问题:当我测试是否已在我触发的事件上调用 stub 时,该 stub 永远不会被调用。例如,当我直接调用 this.view._update 并期望我的 stub likeStubunLikeStub 也被调用时,也会发生这种情况。我已经检查过该元素是否存在,但不明白为什么我的期望失败了。我错过了什么?

我的点赞按钮 View 继承自BaseButton,而BaseButton又继承自base

baz.View.likeButton = baz.View.BaseButton.extend({

template: _.template($('#like-button').html()),
sPaper: null,
sPolyFill: null,
sPolyEmpty: null,
liked: null,
likeButn: null,
model: null,

events: {
"click button.icon": "toggleLike"
},

initialize: function (options) {
// inherit from BaseButton
View.BaseButton.prototype.initialize.apply(this, [options]); // inherit from BaseButtonView

this.model = options.model;
this.liked = this.model.get('liked');

// set initial variables
this.likeButn = this.$("button.icon", this);

// pass in el on instantiation
this.el = options.el;

this.svgNode = this.likeButn.find("svg").get(0); // find the svg in the likeButn and get its first object
this.sPaper = Snap(this.svgNode); // pass the svg object into Snap.js
this.sPolyFill = this.sPaper.select('.symbol-solid');
this.sPolyEmpty = this.sPaper.select('.symbol-empty');

this.likeButn.addClass(this.liked ? "liked": "unliked");

this._update();

if(this.model)
{
this.listenTo(this.model, "change:liked", _.bind(this._modelChange, this))
}
},

render: function () {
this.$el.html(this.template());
this._update();
return this;
},

toggleLike: function () {
this.liked = !this.liked;
this._update();
},

_modelChange: function() {
var bNewState = this.model.get('liked');
if(bNewState !== this.liked)
{
this.liked = bNewState;
this._update();
}
},

_update: function () {
if ( this.liked === true ) { // if liked is false, remove class, add class and set isLiked to true, then animate svg to liked position
this._like();
} else if ( this.liked === false ) { // is liked is false, remove class, add class, set isLiked to false, then animate svg to unliked position
this._unlike();
}
},

_like: function() {
this.likeButn.removeClass("unliked");
this.likeButn.addClass("liked");
this.animateLike();
if(this.model.get('liked') !== true)
{
this.model.set('liked', true);
this.model.set("numLikes", this.model.get("numLikes") + 1);
// wrapper for API
likeEntity("/items/"+this.model.id); // should do something better than this to send like to server
}
},

_unlike: function() {
this.likeButn.removeClass("liked");
this.likeButn.addClass("unliked");
this.animateUnlike();
if(this.model.get('liked') !== false)
{
this.model.set('liked', false);
this.model.set("numLikes", this.model.get("numLikes") - 1);
// wrapper for API
unlikeEntity("/items/"+this.model.id); // should do something better than this to send like to server
}
},

animateLike: function () {
this.sPolyFill.animate({ transform: 't9,0' }, 300, mina.easeinout);
this.sPolyEmpty.animate({ transform: 't-9,0' }, 300, mina.easeinout);
},

animateUnlike: function () {
this.sPolyFill.animate({ transform: 't0,0'}, 300, mina.easeinout);
this.sPolyEmpty.animate({ transform: 't0,0' }, 300, mina.easeinout);
}
});

baz.View.base = Backbone.View.extend({

// initialize variables and render template
initialize: function (options) {
this.render(); // render template and initializes above values
},

render: function () {
return this; // A good convention is to return this at the end of render to enable chained calls.
}
});

baz.View.BaseButton = baz.View.base.extend({

// backbone event hash - sets functions to events on selected buttons
events: {
"click button": "triggered"
},

// initialize variables and render template
initialize: function (options) {
baz.View.base.prototype.initialize.apply(this, [options]); // inherit from base
this.btn = this.$("button.normal-buttons");
},

// fn to be called for normal and cancel buttons
triggered: function (event) {
this.trigger('click', this);
this.btn.blur();
}
});

我的测试代码:

describe("Like Button View", function () {


before(function () {

this.$fixture = $('<div id="likeButton-view-fixture"></div>');

});

after(function () {

$("#fixtures").empty();

});

describe("Like button when attribute 'LIKED' is FALSE", function () {

beforeEach(function () {

// set-up fake server
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;

// empty out and rebind the fixture for each run
this.$fixture.empty().appendTo($("#fixtures"));

this.model = new baz.Model.item({
liked: false,
numLikes: 0
});

this.view = new baz.View.likeButton ({
el: this.$fixture,
model: this.model
});

this.renderSpy = sinon.spy(this.view, "render");

this.updateStub = sinon.stub(this.view, "_update");

this.toggleLikeStub = sinon.stub(this.view, "toggleLike");

this.modelChangeStub = sinon.stub(this.view, "_modelChange");

this.likeStub = sinon.stub(this.view, "_like");

this.unlikeStub = sinon.stub(this.view, "_unlike");

this.animateLikeStub = sinon.stub(this.view, "animateLike");

this.animateUnlikeStub = sinon.stub(this.view, "animateUnlike");

this.snapAnimSpy = sinon.spy(Snap, "animate");

});

afterEach(function () {

this.view.model.destroy();

this.renderSpy.restore();

this.updateStub.restore();

this.toggleLikeStub.restore();

this.modelChangeStub.restore();

this.likeStub.restore();

this.unlikeStub.restore();

this.animateLikeStub.restore();

this.animateUnlikeStub.restore();

this.snapAnimSpy.restore();

// undo our server
this.server.restore();

});

it("call render and view should exist", function () {

var _view = this.view.render();

expect(_view).to.equal(this.view);
expect(this.renderSpy).to.have.been.called;
expect(this.view).to.be.ok;
});

it("should have class 'unliked'", function () {

var _element = $(".icon")[0];

expect(_element.className).to.include("unliked");
});

it("trigger 'toggleLike' when button is clicked should change liked value and call update", function () {

var _event = $.Event("click");

var _element = $(".icon");

_element.trigger(_event);

expect(this.toggleLikeStub).to.have.been.called; // this fails
expect(this.view.model.get("liked")).to.deep.equal(true); // this fails
expect(this.updateStub).to.have.been.called; // this fails

});

it("should like an item", function () {

var _element = $(".icon")[0];

this.view._like();

expect(_element.className).to.include("liked");
});
});
});

最佳答案

好的,所以您这里有多个问题。

  • this.view._update

    This is happening too when I directly call this.view._update for example and expect my stubs likeStub or unLikeStub to be called too.

    这之后你还会这样做吗?:

    this.updateStub = sinon.stub(this.view, "_update");
  • toggleLikeStub

    我认为这是失败的,因为在调用 sinon.stub() 之前,原始的 toggleLike 已被指定为事件处理程序。尝试做这样的事情:

    this.updateStub = sinon.stub(baz.View.likeButton.prototype, "_update");    

    this.view = new baz.View.likeButton ({
    el: this.$fixture,
    model: this.model
    });
  • 你所在的地方:

    expect(this.updateStub).to.have.been.called; // this fails

    updateStub() 不会因调用 toggleLikeStub() 而被调用。来自 documentation for sinon.stub() :

    When wrapping an existing function with a stub, the original function is not called.

    你确定不想要 spy 吗?

  • 杂项

    我只是想确保您知道,而不是这样做:

    this.toggleLikeStub = sinon.stub(this.view, "toggleLike");
    // ..
    this.toggleLikeStub.restore();

    你可以这样做:

    sinon.stub(this.view, "toggleLike");
    // ..
    this.view.toggleLike.restore();

    更好的是,你可以这样做:

    var meths = [
    {sinon_meth: 'stub', view_meths: ['_update', 'toggleLike', ...]},
    {sinon_meth: 'spy', view_meths: ['render', 'animate', ...]},
    ];

    meths.forEach(function (group) {
    group.view_meths.forEach(function (view_meth) {
    sinon[group.sinon_meth](view, view_meth);
    });
    });

    // ...

    meths.forEach(function (group) {
    group.view_meths.forEach(function (view_meth) {
    view[view_meth].restore();
    });
    });

    在这种情况下,如果您在每次测试之前进行相同的设置并清除 this.view,我不确定是否需要恢复它们。

关于javascript - 诗农 stub 未被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29536108/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com