Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Не каждое приложение нуждается в таких вещах как require.JSВозможность, с одной стороны, не засорять глобальный скоуп, а с другой — иметь простой доступ к содержимому модуля для тестирования была для меня одной из причин перейти на require.js.
Проблема в том, что доступ к функции privateMethod извне уже никак не получитьЕсть мнение, что тестировать приватные методы и не нужно. Обоснование — в приватных методах содержатся детали реализации, которые, по определению, юнит-тестами покрывать не надо.
it("...", function() {
var result, fake_data = {....};
spyOn(someObj, "someFn").andReturn("fake data one");
result = someObj.fnThatUsesSomeFn(fake_data);
expect(result).toBe(.....);
spyOn(someObj, "__someFn").andReturn("fake data two");
result = someObj.fnThatUsesSomeFn(fake_data);
expect(result).toBe(.....);
});
Есть мнение, что тестировать приватные методы и не нужно. Обоснование — в приватных методах содержатся детали реализации, которые, по определению, юнит-тестами покрывать не надо.
function ShapeManager() {
var __getSpecificShapeParam = function(shape) {
...// тут какие-то хитрые вычисления, которые зависят от фазы луны и магнитных бурь на солнце.....
}
return {
someMethod1: function(shape) {
var specific_param = __getSpecificShapeParam(shape);
if (specific_param .....) {
return true;
} else {
return false;
}
},
someMethod2: function(shape) {
var specific_param = _getSpecificShapeParam(shape);
.....
}
}
}
if (specific_param .....) {
return true;
} else {
return false;
}
Кажется логичным ответ на вопрос, что надо ставить обработчики данных в одну кучу, обработчики событий в другую. Так я отказываюсь тестировать ту часть которая красит инпут в нужный цвет, а концентрируюсь на том, чтобы сделать возможным протестировать ту часть программы, где вычисляется в какой цвет красить инпут.Это называется разделение бизнес-логики и логики представления. И, скажем, разработчики AngularJS (как наиболее «тестоориентированного» MV*-фреймворка) уже давно позаботились о том, чтобы такие вещи писались и тестировались одним движением левой пятки.
window.location = 'http://habrahabr.ru', вызовы history API и тд. Также как правильно тестировать изменение DOM, тк разные браузеры по разному могут генерить html. И как тестировать jQuery объекты, когда $('.some-class') !== $('.some_class')?namespace.util = {
redirect: function(url) {
window.location = url;
}
}
sinon.spy(utils, "redirect");
//...
expect(namespace.util.redirect).have.been.calledOnce;
namespace.util.redirect.restore();
expect($('h1')).to.be.deep.equal($('h1'));
function Validator(regexp, ajax) {
this.regexp = regexp;
this.ajax = ajax;
}
Validator.prototype.validate = function(str, callback) {
if(/*validate by regexp*/) {
ajax({/*validate on server*/}).success(function(data) {
callback(data)
});
}
else {
callback(false);
}
}
var validator = new Validator(/\d*/, $.ajax);
$('input').on('keydown', validator.validate.bind(validator));
var ajaxMock, validator;
beforeEach(function() {
ajaxMock = jasmine.createSpy('ajax').andReturn({
success: jasmine.createSpy('ajaxSuccess')
});
validator = new Validator(/\d*/, ajaxMock);
});
it('a test', function() {
var callbackSpy = jasmine.createSpy('callback')
validator.validate('123a', callbackSpy);
expect(callback).not.toHaveBeenCalled();
expect(ajaxMock).toHaveBeenCalled();
//вот как-то так можно добраться до скрытой внутри лямбды
ajaxMock.success.mostRecentCall.args[0](true);
//а потом проверить, что она отработала правильно
expect(callbackSpy).toHaveBeenCalledWith(true);
});
ajaxMock = spyOn($, 'ajax'), но тогда получается та самая нечистая функция, поэтому лучше так не делатьvar MyExample = function (options, view) {
var _view = view,
_displayed = false;
this.show = function () {
if (!_displayed) {
_displayed = true;
_view.show();
}
};
this.hide = function () {
if (_displayed) {
_displayed = false;
_view.hide();
}
};
};
documentgetElementById("MyId").style.display = true, а может $("#MyId").fadeIn(2000);.function isFunction(object) {
return object && getClass.call(object) == '[object Function]';
}
function mockObject(obj) {
for(var key in obj)
if(isFunction(obj[key])) {
spyOn(obj, key)
}
}
}
Глубинное погружение в test-driven JavaScript