By: Weikko Aejmelaeus

2012-11-22

Testdriven JavaScript med Knockout.js och QUnit

Moderna webbaserade system har ofta ett relativt avancerat användargränssnitt som innehåller mycket logik. Som .NET utvecklare har jag varit van att använda testdriven utveckling och skriva enhets- och integrationstester i NUnit för logik i backend-delen av systemet.

I ett projekt fick jag som uppgift att utveckla en applikation där det krävdes att mycket av logiken utvecklades i JavaScript. Tidigare erfarenheter av detta har inte varit så bra. Det har blivit ostrukturerad logik blandat med jQuery-selektorer som växt till en stor klump som ingen tillslut vågat röra i.

Knockout.js låter en på ett naturligt sätt separera logik från UI. ViewModel-klassen kan testas med t.ex. QUnit utan användargränssnitt. Tar man sedan med t.ex. Sinon.js som är ett stub/mock-ramverk för JavaScript så har man en välutrustad verktygslåda som låter en göra avancerade enhetster för JavaScript.

Som ett mycket simpelt exempel används en applikation där man kan lägga till ord. Det innehåller i all sin enkelhet ett textfält och en knapp för att lägga till ordet. Programmet visar en Knockout.js-ViewModel och hur den testas med QUnit och Sinon.js
“`
WordsRepository = function () {
this.addWord = function (word) {
// Call some jQuery Ajax or something…
};
};

var WordsViewModel = function (wordRepository) {
this.wordRepository = wordRepository;
this.word = ko.observable(“”);
this.addButtonEnabled = ko.computed(function () {
return this.word().length > 0;
}, this);
this.addWordClicked = function () {
this.wordRepository.addWord(this.word());
};
};

/*
** Tests
*/

var repository;
var viewModel;

module(“WordsTests”, {
setup: function () {
repository = new WordsRepository();
viewModel = new WordsViewModel(repository)
},
teardown: function () {
// Nothing here…
}
});

test(“addButtonEnabled_whenWordIsEmpty_addButtonEnabledIsFalse”, function () {
viewModel.word(“”);
var addEnabled = viewModel.addButtonEnabled();
equal(addEnabled, false);
});

test(“addButtonEnabled_whenWordHasText_addButtonEnabledIsTrue”, function () {
viewModel.word(“SomeWord”);
var addEnabled = viewModel.addButtonEnabled();
equal(addEnabled, true);
});

test(“addWordClicked_whenMethodIsCalled_repositoryCalledWithCorrectWord”, function () {
sinon.stub(repository, “addWord”);
var word = “TheWord”;
viewModel.word(word);
viewModel.addWordClicked();
ok(repository.addWord.calledWith(word));
});
“`

Som .NET utvecklare så var Knockout.js MVVM-tänk bekant från WPF och Silverlight. Så det var relativt lätt att komma igång med den biten.

Nästa steg blir att få med QUnit-testerna med i CI-byggena. Visual Studio 2012 lär ha bättre stöd för externa testbibliotek än sina föregångare, så det borde gå bra!

Happy Testing!

/Weikko
.NET- och JavaScript-utveklare på Dynabyte

#Javascript #Knockout.js #QUnit #Sinon.js #TDD

Mobile application development

En kväll med Windows 8