Добрый день, хабр.
После моего статьи О Попробуй это Это была неделя вечности.
И как бы я ни планировал продлить этот срок хотя бы на месяц, пришло время новой публикации.
Картинка для привлечения внимания:
С тех пор библиотека (во многом благодаря хабравитам) приобрел новый функционал.
И в связи с тем, что синтаксис, приведенный в предыдущей статье, не полностью работает в текущей версии, я не имею права откладывать эту статью еще на 3 недели.
Кто не любит много слов - Веб-сайт где вы можете увидеть код в действии, GitHub , Вики Появилась цепочка звонков
и новый механизм гнездованияtest.it(some) .
comment('comment to test') .
callback(function(){alert('test has been passed')}) .
arguments(); // -> [some] test.group('group', function(){ .
}) .
comment('comment to group') .
result(); // -> true/false
test.group('first group',function(){
.
test.group('second group', function(){
.
});
.
});
test.group('first group').
group('second group',function(){ .
});
Новый способ отображения ошибок
И два дополнительных метода test.typeof() И тест.trace() .
А еще 3 Вики -страницы.
А теперь обо всем этом более подробно.
Так.
Давайте посмотрим на пример, приведенный в вики : Пока мы еще не приступили к тестированию, давайте воспользуемся методом test.typeof() .
console.log(
test.typeof(1)
,test.typeof("text")
,test.typeof([1,2,3])
,test.typeof({a:1,b:2})
,test.typeof()
,test.typeof(document)
,test.typeof(document.getElementsByTagName("body"))
,test.typeof(window)
,test.typeof(/yes it is RegExp/) // and many many more .
);
test.typeof() — определяет тип передаваемого ему значения.
Он может различать: Множество , логическое значение , Дата , Ошибка ( Эвалеррор , ДиапазонОшибка , Ошибка ссылки , Ошибка синтаксиса , ТипОшибка , УриОррор ), Функция , НЭН И Число , Объект , Регэксп , Нить , Окно , HTML , список узлов .
И он также определит пустую переменную как 'неопределенный' но в отличие от стандартного тип не сможет получить необъявленную переменную в качестве аргумента.
Он ответит за это 'неопределенный' к несуществующему свойству объявленного и непустого объекта.
Но это уже специфика языка.
Если мы обновим страницу, в консоли появится следующая строка:
Теперь давайте посмотрим на метод тест.trace() .
(function firstFunction() {
(function secondFunction() {
(function lastFunction() {
console.log(test.trace());
})();
})();
})();
тест.trace() - возвращает список (собраны в строки, разделенные «\n») строки кода, которые были выполнены для вызова этого метода.
На самом деле это не реально след() (чего, к сожалению, нет в JavaScript) , потому что из него были вырезаны все ссылки на вызовы внутри библиотеки.
В вывод консоли теперь будет добавлено следующее:
Здесь и далее несущественные части вывода консоли на скриншотах будут опущены, чтобы бессмысленно не увеличивать размер изображений.
Приступим к тестированию.
Для начала создадим объект для тестов, переменную с целочисленным значением и пустую переменную.
var Family = {
name: "Desiderio",
pet: {
type: "dog",
name: "google"
},
members: [
{
name: "Titulus",
age: 23
},
{
name: "Dude",
age: Infinity
}
]
}
var myIQ = 100;
var Nothing;
Думаю, вопросов по этому коду быть не должно.
Давайте двигаться дальше.
Следующий шаг – первое испытание.
Тест на нефальшь.
Здесь все так же, как и раньше.
test.it("hello world");
test.done();
test.it(значение) — создает новый тест, проверяя ценить к неложности.
тест.done() — завершает тесты и выводит результат на консоль.
В дальнейшем будет считаться, что тест.done() появляется в последней строке нашего кода.
Я буду опускать это в примерах.
В консоли видим:
Где:
- корень — имя группы нулевого уровня.
- pass — статус группы, означающий, что все тесты/группы в ней пройдены успешно.
- 1/0/0 — количество пройденных/неудачных/ошибочных тестов/групп соответственно.
- (9 мс) — время в миллисекундах, потраченное на тесты.
Прежде чем мы рассмотрим наш единственный тест, давайте разберем и его:
Так:
- pass — статус теста, означающий, что он пройден
- аргумент не является ложным — описание типа теста и его результата
- ["Привет, мир"] — массив аргументов, передаваемых в тест
Попробуем использовать механизм цепочность .
Самый простой случай — добавление комментария: test.it(2+2==5)
.
comment("i badly taught algebra at school");
.
комментарий(текст) — добавляет комментарий к тесту/группе, в цепочке которого он был вызван.
При этом продолжая цепочку, но об этом чуть позже.
Этот код также можно записать так: test.it(2+2==5).
comment("i badly taught algebra at school");
Но, для случаев с более длинными цепочками, удобнее и понятнее писать столбиком.
Сейчас корень (расширяется автоматически, поскольку содержит неудавшийся тест) выглядит следующим образом:
В счетчиках в первой строке можно заметить увеличение второй цифры от 0 до 1, что означает увеличение количества неудачных тестов/групп.
Обратим внимание на тот, который открыт по умолчанию.
(потому что он не был принят) , тест. От предыдущего он отличается только статусом «пройден», что означает, что тест провален, и комментарием «Я плохо преподавала алгебру в школе», который мы добавили.
Очевидно, что в test.it(значение) Можно передавать не только строки, но и переменные, выражения, вызовы функций и т. д. В принципе, что бы мы ни передавали, оно сначала будет выполнено, будет получен результат, и этот результат пойдет в тест. Именно так устроен JavaScript. Давайте проверим то, что мы только что сказали.
Давайте проверим выражение: test.it(Infinity>Infinity-1)
.
comment("philosophically is not it?");
Об этом выражении можно подумать за чашкой кофе, мы здесь ради чего-то другого.
Результат теста похож на результат предыдущего, что очевидно.
Пока мы не уйдем в дебри цепных звонков, и мы обязательно уйдем, Давайте посмотрим на другой вариант теста Попробуй это() .
Тест на равенство
Давайте сравним ранее объявленную переменную с другим значением.
test.it(myIQ,"genious")
.
comment("is I'm genious?"); test.it(myIQ,(1+10)*12 - 34 + 5*5*5 - 123) .
comment("check my IQ to be a normal");
test.it(значение1, значение2) — проверяет равенство двух переданных ему значений.
В консоли эти 2 теста будут выглядеть так:
Ничего необычного, но стоит обратить внимание на описание первого (неудачного) теста.
" аргументы имеют разные типы » — в этом тексте содержится подсказка, объясняющая нам, почему тест не удался — переданные аргументы разного типа.
Теперь попробуем более сложные цепочки.
Давайте выполним некоторые действия в зависимости от результата теста.
if (test.it(Family)
.
comment("Is Family exist? Is it not empty?") .
result()) {
console.info("by if: ","Yep! Here it is!");
} else {
console.warn("by if: ","ALARM! there are no Family");
}
.
результат() — завершает цепочку и возвращает результат теста.
В этом коде мы проверяем Семья на нефальшь и в зависимости от результата выводим в консоль разные фразы.
Вывод консоли теперь выглядит так:
Правда, такую задачу предпочтительнее выполнять с помощью другого цепного вызова: test.it(Nothing)
.
comment("Is Nothing exist? Is it not empty?") .
callback(
function(){console.info("by callback: ","Yep! Here it is!");}
,function(){console.warn("by callback: ","ALARM! there are no Nothing");});
.
callback( function(){ /* funcIfpass */}[, function(){ /* funcIffall */}[, function(){ /* funcIferror */}]]) — выполняет одну из трёх функций в зависимости от результата прохождения теста или группы.
При этом продолжая цепочку.
В результате в консоли видим:
Такая конструкция предпочтительнее, поскольку не завершает цепочку.
Группы
Теперь давайте создадим первую группу.
test.group("Empty group",function(){});
test.group( имя, функция() {… } ) - создает новую группу или обращается к существующему и заполняет его тестами, расположенными в функции, переданной в качестве второго аргумента.
Но поскольку никаких тестов не было сдано, группа создается пустая, но со статусом пройдено - потому что в ней нет ни одного непройденного теста.
Прежде чем сделать скриншот, я развернул группу — это видно по поворачивающейся вниз стрелке и двум серым пикселям, указывающим ее конец.
Но поскольку группа пуста, похоже, что она закрытая.
Хорошо.
Перейдем к более осмысленным действиям.
Давайте создадим группу с двумя тестами внутри и комментарием.
test.group('Family tests',function(){
test.it(Family.name,"Zukerberg")
.
comment("Are we test Zukerberg's family?"); test.it(Family.name,"Desiderio") .
comment("Or Desiderio's?"); }).
comment("unite!");
Видите – ничего сложного!
Здесь вам просто нужно обратить внимание на комментарий, который мы добавили объединяйтесь! - в шапке группы.
Теперь попробуем проделать трюк с ушами и добавим несколько тестов в уже созданную группу.
И не просто тесты, а тесты, инициирующие новые тесты в зависимости от их результата.
Добавим следующий код: test.group("Family tests",function(){
test.it(Family.pet)
.
comment("Do we have a pet?") .
callback(function(){ // I add test in your test, so you can test while you testing test.it(Family.pet,{type:"dog", name:"google"}) .
comment("Is it right pet?"); }); test.it(Family.house) .
comment("Do we have a House?") .
callback(function(){ // next test will not be executed test.it(Family.pet,{type:"Huge", color:"green"}) .
comment("Is it right House?");
});
});
Принимая во внимание последние 2 теста в этой группе и еще 4 только что описанных теста, всего их будет 5 (sic!).
Проверить это можно на калькуляторе.
Вы видите это в названии? 3 прошли, 2 не прошли - всего 5.
Новые тесты
Пришло время взглянуть на парочку необычных тестов.
Для начала в группе «А вот и странные тесты» Давайте создадим следующие два теста: test.them([Family.pet, Family.members])
.
comment("There must be memebers with pet, to call it a 'Family'"); test.types([Family.pet.name, Family.name],"string") .
comment("Is names are string type");
test.them(значения) - аналог test.it(значение) , только в качестве первого аргумента он принимает массив, в котором уже проверяет элементы на неложность.
test.types(значения [, тип]) - а также test.them(значения) проверяет элементы массива, переданные в качестве первого аргумента.
Но он проверяет их на соответствие типа, и если передан второй аргумент тип - затем берет этот тип за образец.
У этого теста есть упрощенный аналог, но об этом чуть позже.
Вот как они выглядят в консоли:
Я для ясности открыл тесты вместе с их массивами аргументов, но мне почему-то кажется, что ясность от этого только уменьшилась.
И вот вам еще одна цепочка магии: var numberOfMembers = test.type(Family.members,"Array")
.
comment("Is it a several members, nor a single member?") .
arguments()[0].
length; test.it(numberOfMembers>5) .
comment("Is it big family?");
.
аргументы() — завершает цепочку вызовов и возвращает переданные в тест аргументы ( не в группе! ).
Поясню - первый тест, проверил значение Семья.
члены не ложь.
Поскольку это массив из двух элементов, тест пройден.
аргументы()[0] == Семья.
члены .
Поэтому в переменную количество членов вводится количество элементов массива Семья.
члены то есть 2. Второй тест не пройден из-за того, что 2 не больше 5.
Вложение
Ты еще помнишь, что мы в группе» вот и странные тесты "? Добавим сюда еще одну группу и сразу воспользуемся конструкцией для для создания нескольких однотипных тестов.
test.group("Members age",function(){
for (i=0;i<numberOfMembers;i++) {
test.it(Family.members[i].
age>25) .
comment("Is "+Family.members[i].
name+" older then 25?");
}
});
Теперь эта новая группа" Возраст участников «расположен в старом» вот и странные тесты ".
Ошибки
Давайте добавим в одну группу" Возраст участников «Еще один тест: test.it()
.
comment("yep, here is error");
Этот код приведет к ошибке, потому что Попробуй это() ожидает получить от 1 до 2 аргументов.
В заголовке ошибки:
- RangeError — тип ошибки
- ожидается хотя бы один аргумент — описание, помогающее понять причину его возникновения.
И сам объект ошибки в данном случае ДиапазонОшибка - это если кто-то хочет вникнуть поглубже.
Ссылки на группы
Вернёмся на уровень корень .
На всякий случай напомню, что группа " вот и странные тесты "сейчас выглядит так:
В нем есть еще одна группа» Возраст участников «.
Теперь мы добавим в него тест. test.group("here comes strange tests").
group("Members age",function(){ test.it("bye") .
comment("good");
});
test.group(имя) — возвращает ссылку на группу, после чего ее можно использовать как начало цепочки, для добавления новой группы тестов или добавления тестов в существующую подгруппу.
Это последнее, что мы только что сделали.
Теперь в консоли мы видим:
И напоследок, чтобы закрепить все вышесказанное: полный список со всеми выводами консоли console.log( // look how do test.typeof() work
test.typeof(1)
,test.typeof("text")
,test.typeof([1,2,3])
,test.typeof({a:1,b:2})
,test.typeof()
,test.typeof(document)
,test.typeof(document.getElementsByTagName("body"))
,test.typeof(window)
,test.typeof(/yes it is RegExp/));
(function firstFunction() { // look how do test.trace() work
(function secondFunction() {
(function lastFunction() {
console.log(test.trace());
})();
})();
})();
var Family = { // Here some complex object
name: "Desiderio",
pet: {
type: "dog",
name: "google"
},
members: [
{
name: "Titulus",
age: 23
},
{
name: "Dude",
age: Infinity
}
]
}
var myIQ = 100; // and value
var Nothing; // and empty value
test.it("hello world"); // Let"s add some simple tests
test.it(2+2==5).
comment("i badly taught algebra at school"); // with comment test.it(Infinity>Infinity-1).
comment("philosophically is not it?"); // with expression // check equalence test.it(myIQ,"genious").
comment("is I'm genious?"); test.it(myIQ,(1+10)*12 - 34 + 5*5*5 - 123).
comment("check my IQ to be a normal"); // try some chain staff if (test.it(Family).
comment("Is Family exist? Is it not empty?").
result()) { console.info("by if: ","Yep! Here it is!"); } else { console.warn("by if: ","ALARM! there are no Family"); } // do it again in better way test.it(Nothing).
comment("Is Nothing exist? Is it not empty?").
callback( function(){console.info("by callback: ","Yep! Here it is!");} ,function(){console.warn("by callback: ","ALARM! there are no Nothing");}); test.group("Empty group",function(){}); // try to make a group test.group('Family tests',function(){ // let's unite it! test.it(Family.name,"Zukerberg").
comment("Are we test Zukerberg's family?"); test.it(Family.name,"Desiderio").
comment("Or Desiderio's?"); }).
comment("unite!"); test.group("Family tests",function(){ // and add some test after test.it(Family.pet).
comment("Do we have a pet?") .
callback(function(){ // I add test in your test, so you can test while you testing test.it(Family.pet,{type:"dog", name:"google"}).
comment("Is it right pet?"); }); test.it(Family.house).
comment("Do we have a House?") .
callback(function(){ // next test will not be executed test.it(Family.pet,{type:"Huge", color:"green"}).
comment("Is it right House?"); }); }); test.group("here comes strange tests",function(){ // test existance of most important Family properties test.them([Family.pet, Family.members]) .
comment("There must be memebers with pet, to call it a 'Family'"); // test types of names test.types([Family.pet.name, Family.name],"string") .
comment("Is names are string type"); // here some magic var numberOfMembers = test.type(Family.members,"Array") .
comment("Is it a several members, nor a single member?") .
arguments()[0].
length; test.it(numberOfMembers>5).
comment("Is it big family?"); // So if we know how many members there, lets check their age test.group("Members age",function(){ for (i=0;i<numberOfMembers;i++) { test.it(Family.members[i].
age>25) .
comment("Is "+Family.members[i].
name+" older then 25?"); } test.it().
comment("yep, here is error"); // add some error to see the trace }); }); // add final test deep in group test.group("here comes strange tests").
group("Members age",function(){ test.it("bye").
comment("good");
});
test.done();
корень
О, да.test.root до сих пор лежит на своем месте.
Его также можно использовать для создания новых вариантов отображения результатов.
Он был немного упрощен (счетчики групп больше не разделяют группы и тесты).
Пустой корень выглядит так: {
"type": "group",
"name": "root",
"time": 0,
"result": {
"pass": 0,
"fail": 0,
"error": 0,
"total": 0
},
"stack": []
}
Заключение
Мне бы очень хотелось поблагодарить:- верблюды И зорро1211 для идей цепного звонка
- верблюды отдельно за идею .
перезвонить
- Анонимный за идею доступа к группе извне.
в том числе из других файлов.
Но уже есть очень интересные мысли о методах их решения.
Веб-сайт где вы можете увидеть весь приведенный выше код в действии, GitHub , Вики Теги: #JavaScript #tdd #тестирование #открытый исходный код #JavaScript #tdd
-
Успешный Ввод Законных Данных
19 Oct, 24 -
Такой Страшный Симметричный Nat
19 Oct, 24 -
Linux В Организации...
19 Oct, 24 -
Гугл Калькулятор На Русском Языке
19 Oct, 24 -
Секреты Дизайна Проектов Web 2.0
19 Oct, 24 -
Правильное Использование Исключений В Java
19 Oct, 24