node.js moduly a testovanie
TRANSCRIPT
Kto sme
Online marketing
Robili sme:● M 2 N affiliate platformu● campaign management and reporting ● tag management● campaign attribution / selective cookie call● ad server with different targeting models including behavioral targeting
Teraz robime @novosense:● Persistent user tracking platformu● Cloud cookie● Realtime activity maps & user engagement
Technologicky stack
Server:● Node.js (predtym nativne Apache moduly)● Python
Data:● Cassandra● Redis● Couchbase
Komunikacia:● RabbitMQ
a samozrejme aj PHP a MySQL ;)
Moduly
Jasna vec deporkifikacia kodu / DRY, znovupouzitelnost, izolacia kodu a decoupling, vyssia kombinovatelnost
Druhy modulov v Node.js*:● c/c++ binding● kniznica● command line program● server / website (nie framework - uz kompletna implementacia)
Nevynaliezajte "koleso":● https://github.com/joyent/node/wiki/Modules kategorizovany zoznam● http://search.npmjs.org/ a http://toolbox.no.de/ vyhladavace
* Podla http://howtonode.org/how-to-module
Balicky (CommonJS 1.0)
npm [http://npmjs.org/doc/]● kto "Noduje" tak sa s nim stretol● od Node.js v0.6+ bundlovany s Node● CLI sprava a distribucia balickov● popisuje interface k balickom prostrednictvom package.json suboru v
roote projektu
Co je balicek (a formy distribucie pre npm install)● adresar obsahujuci program popisany package.json● tar.gz obsahujuci package.json alebo URL na tar.gz● meno / meno@verzia / meno@tag publishnuty v NPM registri● GIT repository obsahujuce package.json
Privatny NPM register? Da sa http://npmjs.org/doc/registry.html
Struktura balicku (layout podla CommonJS)
/bin spustitelne subory
/doc/example/lib tu prebyva nas modul / javascript kod
/test.npmignore funguje ako .gitignore
index.js automaticky berie ako main include pre adresar
package.jsonREADME.md slusnost kaze zvlast ak chceme npm publish
package.json [http://npmjs.org/doc/json.html]
npm init je carovny :) a interaktivny
About to write to /Users/daniel/Desktop/todo/rubyslava/package.json
{
"author": "kolektiv autorov :)",
"name": "simple_remote_logger",
"description": "Intended to be used as remote javascript console.",
"version": "0.0.1",
"main": "./index",
"scripts": {
"test": "mocha test/*.js"
},
"engines": {
"node": "~0.6.7"
},
...
package.json rucne upravy
Semantic version ranges http://npmjs.org/doc/json.html#dependencies
podla potreby doplnime zavislosti"dependencies" : {
"commander" : "=0.6.x" // doporucuje sa }
vyvojove zavislosti test fw, docu fw..."devDependencies" : {
"mocha" : "" // matches any version}
ak ideme npm publish pridame keywords"keywords" : ["remote", "console"]
package.json goodies
● "files" pole definijuce subory / adresare ktore ma projekt obsahovat, toto je lepsie riesit asi cez .npmignore
● "bin" kolekcia spustitelnych suborov ktore sa maju nainstalovat do PATH
● "scripts" script commandy spustitelne v roznych fazach zivotneho cyklu balicka
● "config" konfiguracne parametre pre scripty
● "publishConfig": {"registry": URL } prikaze publikovat do definovaneho registra
● "private" true / false povoluje alebo zamedzuje publikovanie balicka vo vseobecnosti
module.exports
Lokalne premenne modulu su privatne. Nedeklarujeme NIC bez var lebo zmrsime global scope. Ako rozhranie modulu sluzi module.exports. Je to objekt (kolekcia) zdielany medzi vsetkymi "instanciami" modulu.
var default_name = 'John';var say_hello = function(name) { console.log('Hello ' + (name ? name : default_name) + '!'); };module.exports.def_name = default_name;module.exports.say = say_hello;
Priradit mu ale mozeme aj akykolvek platny Javascript typ (boolean, number, date, string, function, array, object etc.)
var Server = function(resource_path) { ... }module.exports = Server;
exports vs. module.exports
exports nepouzivat !!!, je to vlastne "alias" vytvoreny k module.exports. Module system za nas urobi
var exports = module.exports;
Pokial pridavame properties tak je to ok. Akonahle ale chceme priradit nieco "by assignment" tak vlastne len prepiseme referenciu na module.exports a modul exportuje prazdny objekt.
exports = 'jezisko'; // jezisko von nepride
zauzivane je exports = module.exports = ...
require()
Nacita modul a vrati jeho exports. Moduly su cachovane po prvom nacitani, takze kazdy call require('moj_modul') vrati ten isty objekt (vynimka moze byt ak exportujeme "by assignment" - tam zalezi od toho co priradime priamo do module.exports).
var greeting = require('./say_hello');var def_name = require('./say_hello').def_name; // priame require konkretnej property exportu modulu je moznegreeting.say();
$ node main.jsHello John!
require()
Tri sposoby pouzivania require● var foo = require('./lib/foo') relativna cesta● var foo = require('/home/foo/lib/foo') absolutna cesta● var foo = require('foo') search
Pri loadovani modulov idealne pouzivat search - drzat sa pravidla ze vsetky dependencies by mali byt instalovane lokalne (voci danemu modulu).
Require cohokolvek v ramci modulu (okrem modulov) relativne.http://npmjs.org/doc/faq.html#Why-can-t-npm-just-put-everything-in-one-place-like-other-package-managers
Process.NextTick
Sluzi na odlozenie vykonania ulohy, callbacku do dalsieho cyklu event loopu (narocne CPU tasky je ale idealne oddelit do zvlast procesu - s nimi mozeme komunikovat tiez cez eventy, eventualne pouzit WebWorkers). Tak neblokuje vykonavany kod a je vykonany skutocne asynchronne.
var net = require('net');var client = net.connect(8124, function() { //'connect' listener console.log('client connected'); client.write('world!\r\n');});
npm finticky
npm link / npm unlink (alebo vymazat symlink)Ak mame modul ktory je vyvoji a nie je publishnuty tak jednoduchsie ako ho stale instalovat je pouzit npm link. To vytvori symlink v global mode. Potom ho mozeme linkovat kde potrebujeme / odkazovat nan v dependencies.
npm root podla adresara v ktorom sa nachadzame nam vypise kde idu moduly
npm pack z hocicoho instalovatelneho vytvori tarball
npm prune vycisti node_modules od balikov ktore nie su v dependencies
Testovanie
Znova jasna vec● odhalovanie chyb● chyby po update● opatovne zanesenie chyb● test funkcionality robi to to co ma?
● automatizacia nech na to mysli stroj a nie ja
Najbeznejsie sa stretavame s● unit testmi funkcie, subrutiny, metody
● funkcnymi testmi cely program s roznymi vstupmi
Testy? Bitch please...
"Test je prvy pouzivatel tvojho kodu."
Zakladne pravidla testov● F ako Fast Preco hrate CS? Lebo bezia testy :).
● I ako Isolated Test ma testovat iba jedno spravanie a ma byt izolovany.
● R ako Repeatable Musi vratit vzdy rovnake vysledky.
● S ako Self-Verifying Ma zlyhat koli jednoznacnemu dovodu.
● T ako Timely Testy sa pisu predtym ako je hotovy produkcny kod.
pisanie Test-After Development je evil
Ako ich pisat v Javascripte
Netestovat privatne metodyassertEqual(val, component._pseudoPrivateFunc());
Netestovat privatny statusassertEqual(val, component._pseudoPrivateAttribute);
Netestovat privatne zavislostivar obj = new FooComponent();var spy = sinon.spy(obj.dependency._pseudoPrivateFunc);obj.doSomething();assertTrue(spy.called);
Ako ich pisat v Javascripte contd.
Netestovat viacere operacie v jednom testeobj.doSomething();this.assertEqual(expected, obj.attr);obj.doSomethingElse();this.assertEqual(different, obj.attr);
Mocknut vsetky zavislostivar dep = sinon.mock({mockedFunc: function() {return true;}});objToTest.setDep(dep);
Testovat spravanie public interface objektu
Test styles TDD (xUnit)
buster.testCase("My thing", { "foo": function () { assert.equals(foo, "bar"); },
"state": function () { assert(true); }})
my sme zvyknuti na xUnit
Test styles BDD
describe("My thing", function () { it("equals of foo and bar failes", function () { expect("foo").toEqual("bar"); });
it("states the obvious", function () { expect(true).toBe(true); });});
Test styles qUnit
test("a basic test example", function() { ok(true, "this test is fine"); var value = "hello"; equals("hello", value, "We expect value to be hello");});
module("Module A");
test("first test within module", 1, function() { ok(true, "all pass");});
Test runners
Je ich vela, "uceleny" framework existuje v beta verzii.
Najznamejsie● mocha● buster● vows● zombie.js● jsTestDriver
Zacali sme s mocha lebo ma runner pre kazdy styl, vela reporterov (pristavanie lietadla), code coverage report, nezavislost od assertovacej libky. Nema assertation count :(
Assertations
O tomto je testovanie.
Najznamejsie● chai.js● should.js
Idealny stav je jeden assert v teste (I ako Isolated). Nie vzdy to musi byt pravidlo.
Message ma pomoct pri pochopeni assertu.
Spy, Stub and Mock
● simulovanie zavislosti● overovanie volani● predprogramovane ocakavania
Ale nie privatnych!
Ak to test vyzaduje moze to znamenat ze objekt je moc zlozity. Treba porozmyslat nad rozdelenim logiky do viacerych objektov (zavislosti), ktore uz ide mocknut lahko.
Buster
"Uceleny" framework v pouzitelnej verzii.
Spaja vsetky skvele funkcie ostatnych runnerov do jedneho.
● testovanie v node aj v browseroch (aj vo viacerych naraz)
● assertations and refutes (minitest v ruby)● obsahuje sinon.js a podporuje definiciu vlastnych
asertacii● moznost automatizacie● ...● bude aj podpora BrowserStack