使用 jasmine 进行 SpyOn 骨干视图方法

发布于 2024-12-11 23:46:18 字数 1316 浏览 0 评论 0原文

我有一个主干视图,我想创建一个测试来确认某个元素上的单击事件将调用绑定到该元素的函数。 我的观点是:

PromptView = Backbone.View.extend({
        id:"promptPage",
        attributes:{
            "data-role":"page",
            "data-theme":"a"
        },
        events:{
            "click #btnYes":    "answerYes",
            "tap #btnYes":      "answerYes"
        },
        render: function(){
            $(this.el).html(_.template($('#promptPage-template').html(), this.model.toJSON()));

            return this;
        },
        answerYes: function(){
            alert('yes');
        }
    });

我的规范是:

beforeEach(function() {
            model = new PromptModel;
            view = new PromptView({model:model});
            loadFixtures('promptPage.tmpl');
        });

 it("should be able to answer a question with yes", function() {
                var button = $("#btnYes", view.render().el);
                expect(button.length).toBe(1);

                spyOn(view, 'answerYes');

                button.click();
                expect(view.answerYes).toHaveBeenCalled();

            });

但是上面的视图定义在原型 proto 上创建了 answerYes 方法,但是间谍在视图中的实际实例上创建了一个函数,所以我最终得到了一个视图.answerYes() 是间谍,而 view.__proto__.answerYes 是我真正想要监视的。

如何创建一个间谍以便它覆盖视图定义的answerYes 方法?

I have a backbone view and I want to create a test to confirm that a click event on some element will call the function bound to that element.
My view is:

PromptView = Backbone.View.extend({
        id:"promptPage",
        attributes:{
            "data-role":"page",
            "data-theme":"a"
        },
        events:{
            "click #btnYes":    "answerYes",
            "tap #btnYes":      "answerYes"
        },
        render: function(){
            $(this.el).html(_.template($('#promptPage-template').html(), this.model.toJSON()));

            return this;
        },
        answerYes: function(){
            alert('yes');
        }
    });

My spec is:

beforeEach(function() {
            model = new PromptModel;
            view = new PromptView({model:model});
            loadFixtures('promptPage.tmpl');
        });

 it("should be able to answer a question with yes", function() {
                var button = $("#btnYes", view.render().el);
                expect(button.length).toBe(1);

                spyOn(view, 'answerYes');

                button.click();
                expect(view.answerYes).toHaveBeenCalled();

            });

However the above view definition creates the answerYes method on the prototype proto , but the spy creates a function on the actual instance in the view, so I end up with a view.answerYes() which is the spy and view.__proto__.answerYes, which is the one I actually want to spy on.

How can I create a spy so that it overrides the answerYes method of the view definition?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

勿忘初心 2024-12-18 23:46:18

嗨,我今天遇到了同样的问题。我刚刚找到了解决方案,在创建间谍方法(回答是)后,您必须刷新视图的事件才能调用新的间谍方法;):

[...]

    spyOn(view, 'answerYes');
    view.delegateEvents();

    button.click();
    expect(view.answerYes).toHaveBeenCalled();

[...]

有关委托事件的更多信息

玩得开心!

Hi I had today the same problem. And I have just found the solution, after creating the spyed method (answerYes) you have to refresh the events of the view to call that new spyed method ;) :

[...]

    spyOn(view, 'answerYes');
    view.delegateEvents();

    button.click();
    expect(view.answerYes).toHaveBeenCalled();

[...]

More information about delegate events

Have fun!

倾城花音 2024-12-18 23:46:18

我通常喜欢假设框架代码已经做了它应该做的事情,并且只测试我对它的使用,所以我发现进行验证事件哈希的测试是可以接受的。如果我发现自己为了测试我的东西(例如委托事件)而重复主干功能,那么也许我比我真正需要的更接近集成测试。我还大量使用原型,以便在单元测试中成为超级隔离女士。当然,拥有一个完成所有这些练习的集成层仍然很重要,但我发现反馈循环对于测试驱动阶段来说太长了。

I generally like to assume that the framework code already does what it ought to and only test my use of it, so I find it acceptable to have a test verifying the events hash. If I find myself duplicating backbone functionality in order to test my thing (like delegating events), then maybe I'm a step closer to integration tests than I really need to be. I also make heavy use of the prototype in order to be super-isolation lady in my unit tests. Of course, it is still important to have an integration layer that does all of that exercising, but I find the feedback loop too long for the test driving phase.

月下客 2024-12-18 23:46:18

这会在 PromptViewanswerYes 方法上创建一个间谍:

spyOn(PromtView.prototype, 'answerYes');

This creates a spy on the answerYes method of the PromptView:

spyOn(PromtView.prototype, 'answerYes');
纸短情长 2024-12-18 23:46:18

TL;DR:监视实例方法,而不是原型。

我认为你需要以不同的方式设置你的测试。 it 块中有太多的担忧和太多的期望,而且还污染了全局命名空间,这可能会导致测试出现问题。

beforeEach(function() {
  loadFixtures('promptPage.tmpl');

  var model = new PromptModel();
  this.view = new PromptView({model:model});
  this.view.render();

  this.button = this.view.$("#btnYes");
});

it("should render the button", function(){
  expect(this.button.length).toBe(1);
});

it("should be able to answer a question with yes", function() {
  spyOn(this.view, 'answerYes');

  this.button.click();
  expect(this.view.answerYes).toHaveBeenCalled();
});

您并不严格需要对按钮长度的期望。如果按钮没有长度(未找到),您将遇到其他失败。但您可能希望它存在,以便更容易地找出视图未正确渲染的情况。

您还应该监视 view 实例,就像您一直在做的那样。 PromptView 的定义确实向原型添加了一个 answerYes 方法,是的,但是您要监视的是视图实例,而不是原型。

如果您监视原型的方法,那么每次您尝试在测试中使用此视图时,answerYes 方法都将是监视方法,而不是实际方法。这听起来不错,但会导致问题,因为多次调用此方法时您将无法访问有效的间谍数据。它只会累积对该一名间谍的所有呼叫。如果您尝试两次监视原型方法,您最终可能会得到一个间谍的间谍,这将是一件奇怪的事情,并且可能会导致问题。

TL;DR: Spy on the instance method, not the prototype.

I think you need to set up your test differently. There are too many concerns and too many expectations in the it block, and you're also polluting the global namespace, which can cause problems with tests.

beforeEach(function() {
  loadFixtures('promptPage.tmpl');

  var model = new PromptModel();
  this.view = new PromptView({model:model});
  this.view.render();

  this.button = this.view.$("#btnYes");
});

it("should render the button", function(){
  expect(this.button.length).toBe(1);
});

it("should be able to answer a question with yes", function() {
  spyOn(this.view, 'answerYes');

  this.button.click();
  expect(this.view.answerYes).toHaveBeenCalled();
});

You don't strictly need the expectation on the button's length. If the button has no length (not found), you'll get other failures. But you might want it there to make it easier to figure out the the view didn't render correctly.

You should also be spying on the view instance, as you've been doing. The definition of PromptView does add a answerYes method to the prototype, yes, but the one that you want to spy on is the view instance, not the prototype.

If you spy on the prototype's method, then every time you try to use this view in your tests, the answerYes method will be the spy, not the actual method. This may sound nice, but it will cause problems as you won't have access to valid spy data when you call this method multiple times. It will simply accumulate all of the calls on that one spy. If you try to spy on the prototype method twice, you may end up with a spy of a spy, which would be a strange thing and could cause problems.

累赘 2024-12-18 23:46:18

如果您在使用间谍On时遇到问题,您可以考虑创建一个间谍。所以像这样:

var eventSpy;
eventSpy = jasmine.createSpy('eventSpy');
view.$el.on('myCustom:event', eventSpy);

If you have trouble using spyOn, you could consider creating a spy. So something like:

var eventSpy;
eventSpy = jasmine.createSpy('eventSpy');
view.$el.on('myCustom:event', eventSpy);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文