Подтвердить что ты не робот

Вырезать вызов селектора jQuery?

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

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

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

4b9b3361

Ответ 1

Проблема заключается в том, что $() - это функция, которая возвращает объект с помощью метода 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);
}

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

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

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, вы можете просто протестировать свою логику приложения, не создавая тем же самым доменом, что и в своем приложении.

Ответ 2

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

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

например,

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

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

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

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

obj = {
  value: "blah",
  type: "text",
  nodeName: "input",
}
$(obj).val(); // "blah"

Ответ 3

Вот довольно хорошее руководство по тестированию ваших просмотров, если вы используете 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();

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

Вот простой пример структуры приложения 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, если вы еще не обнаружили его внутри одного из представлений.