Остановить вызов селектора jQuery? - PullRequest
22 голосов
/ 15 декабря 2011

Я пытаюсь стать лучше при модульном тестировании моего JavaScript.У меня есть следующий код:

var categoryVal = $('#category').val();
if (categoryVal === '') { 
    doSomething();
} 

У моего тестового бегуна нет ввода #category на странице, так как бы мне заглушить / смокировать селектор jQuery здесь?Я просмотрел документацию jasmin и sinon , но не могу понять, как заставить их работать здесь, поскольку их заглушки работают с объектами, которые $нет.

Ответы [ 3 ]

35 голосов
/ 16 декабря 2011

Проблема в том, что $() - это функция, которая возвращает объект с методом val().Таким образом, вы должны заглушить $ (), чтобы вернуть объект-заглушку, имеющий метод val.

$ = sinon.stub();
$.withArgs('#category').returns(sinon.stub({val: function(){}}));

Но главная ошибка здесь - позволить коду, который вы хотите проверить, вызвать функцию $ () для создания новогоэкземпляров.Зачем?Лучше всего не создавать новые экземпляры в вашем классе, а передавать их в конструктор.Допустим, у вас есть функция, которая будет получать значение из входных данных, удваивать его и записывать обратно в другое:

function doubleIt(){
    $('#el2').val(('#el1').val() *2);
}

В этом случае вы создаете 2 новых объекта, вызывая $().Теперь вам нужно заглушить $(), чтобы вернуть макет и заглушку.Используя следующий пример, вы можете избежать этого:

function doubleIt(el1, el2){
    el2.val(el1.val() *2);
}

Хотя в первом случае вы должны заглушить $, чтобы вернуть заглушку, во втором случае вы можете легко передать заглушку и шпиона в вашу функцию..

Итак, тест sinon для второго будет выглядеть так:

var el1 =  sinon.stub({val: function(){}});
    el1.returns(2);

var el2 = sinon.spy({val: function(){}}, 'val')

doubleIt(el1, el2)

assert(el2.withArgs(4).calledOnce)

Итак, поскольку у вас нет элементов dom, вы можете просто протестировать логику приложения без необходимостисоздайте тот же дом, что и в вашем приложении.

10 голосов
/ 30 марта 2012

jQuery использует механизм выбора css Sizzle под капотом и был отсоединен, поэтому есть только несколько мест, где он цепляется. Вы можете перехватить это, чтобы избежать какого-либо взаимодействия с домом.find является важным, чтобы изменить, чтобы ответить всем, что вы хотите.Здесь можно использовать Sinon или временно отключить функцию.

Например,

existingEngine = jQuery.find
jQuery.find = function(selector){ console.log(selector) }
$(".test")
//>> ".test"
jQuery.find = existingEngine

Вы также можете применить определенное условие улова с отступлением

existingEngine = jQuery.find
jQuery.find = function(selector){
  if(selector=='blah'}{ return "test"; }
  return existingEngine.find.apply(existingEngine, arguments)
}

В моемВ недавней работе я создал фиктивный объект, который отвечает как dom-узел, и обернул его в объект jQuery.Это тогда ответит на val () правильно и предоставит все методы jquery, которые он ожидает.В моем случае я просто извлекаю значения из формы.Если вы делаете реальные манипуляции, вам, возможно, понадобится быть более умным, чем это, возможно, создавая временный dom-узел с jQuery, который представляет то, что вы ожидали.

obj = {
  value: "blah",
  type: "text",
  nodeName: "input",
}
$(obj).val(); // "blah"
1 голос
/ 16 декабря 2011

Вот довольно хорошее руководство по тестированию ваших представлений, если вы используете Backbone.js и Jasmin. Прокрутите вниз до раздела «Просмотр».

http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html

Правда, заглушки работают на объектах. Я думаю, смысл создания заглушки вида вот так.

this.todoViewStub = sinon.stub(window, "TodoView")
        .returns(this.todoView);

Это просто, чтобы иметь возможность позже визуализировать представление.

this.view.render();

Другими словами, добавьте div "#category" к DOM тестирующего, чтобы $ мог на него воздействовать. Если ваш div «#category» отсутствует в this.view, то вы, вероятно, можете просто создать страницу test.html, на которой вы запустите свой изолированный тест. Это общий шаблон в структуре Javascript MVC, который я более привык к этой магистрали.

Вот простой пример структуры приложения JMVC:

/todo
   /models
      todo.js
   /list
      /views
         init.tmpl
         listItem.tmpl
      list.css           
      list.js        (Controller)
      unitTest.js    (Tests for your list.)
      list_test.html (A html for your unit tests to run on.)

Имея эту настройку, вы можете просто включить div "#category" в свой list_test.html, если у вас его еще нет внутри одного из представлений.

...