Published on

Javascript Testing with Node.js, Testacular & Jasmine

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide


  1. 1. TestacularJavascript Testing withNode.js, Testacular & Jasmine
  2. 2. "Man, I just love unit tests, Ive just been able to makea bunch of changes to the way something works, andthen was able to confirm I hadnt broken anything byrunning the test over it again..."
  3. 3. 1. Unit Tests allow you to make big changes to code quickly. You know it works now because youverun the tests, when you make the changes you need to make, you need to get the tests workingagain. This saves hours.2. TDD helps you to realise when to stop coding. Your tests give you confidence that youve doneenough for now and can stop tweaking and move on to the next thing.3. The tests and the code work together to achieve better code. Your code could be bad / buggy.Your TEST could be bad / buggy. In TDD you are banking on the chances of BOTH being bad /buggy being low. Often its the test that needs fixing but thats still a good outcome.4. TDD helps with coding constipation. When faced with a large and daunting piece of work aheadwriting the tests will get you moving quickly.5. Unit Tests help you really understand the design of the code you are working on. Instead ofwriting code to do something, you are starting by outlining all the conditions you are subjectingthe code to and what outputs youd expect from that.Why Unit Test Javascript? part 1
  4. 4. 6. Unit Tests give you instant visual feedback, we all like the feeling of all those green lights whenweve done. Its very satisfying. Its also much easier to pick up where you left off after aninterruption because you can see where you got to - that next red light that needs fixing.7. Contrary to popular belief unit testing does not mean writing twice as much code, or codingslower. Its faster and more robust than coding without tests once youve got the hang of it. Testcode itself is usually relatively trivial and doesnt add a big overhead to what youre doing. This isone youll only believe when youre doing it :)8. I think it was Fowler who said: "Imperfect tests, run frequently, are much better than perfecttests that are never written at all".9. Good unit tests can help document and define what something is supposed to do10. Unit tests help with code re-use. Migrate both your code AND your tests to your new project.Tweak the code till the tests run again.Why Unit Test Javascript? part 2
  5. 5. ● Sanity testing - Are the expected functions andclasses available?● Regression testing - Is that bug squashed, and willnever appear again?● Functional testing - Given x, do y.● Specification tests - I dont have real world data,but assuming I get data in this format...● Edge-case testing - This expects a Number, but ifsomeone gives it a String...Why do we use Unit Testing?
  6. 6. Running Tests
  7. 7. ● Developed + Open Sourced by Google.● Node.js === Native Javascript, using the V8 framework.● Works with any* browser.● Works without any IDE.● Integration with CI servers.● Stable.● Fast.● Line, branch, statement & function coverage testdata.● Jasmine, Mocha & AngularJS testing frameworks.Why Testacular?
  8. 8. ● It cant evaluate code coverage in any moredepth than line coverage.● Its Java based.● Slower than Testacular.Why not JSTestDriver?
  9. 9. ● Configuration file specifies:○ Input files (source code and test files)○ Browsers to test with○ Excluded files, coverage tests, ports, run mode, output format, base path, etc...● Command line execution:> testacular startHow does it work?
  10. 10. Lets see that in action...
  11. 11. Writing Tests
  12. 12. Sanity testing/js/rio.jsvar RIO = {init: initialise,model: new RIOModel(),data: new RIOData(),controller: new RIOController()};/tests/rio.tests.jsdescribe("RIO Object", function() {it("has the expected API", function() {expect(RIO).toBeDefined();expect(typeof(RIO)).toBe("object");expect(typeof(RIO.init)).toBe("function");expect(typeof(RIO.model)).toBe("object");expect(typeof(RIO.data)).toBe("object");expect(typeof(RIO.controller)).toBe("object");});});
  13. 13. Regression testing/tests/regression.test.jsdescribe("Defect DE248 Regression test", function() {beforeEach(function() {readFixtures(simple-fixture.html);var options = {containerElement: $(div.sample-1),dataProvider: Standalone.DataProvider,pathToAssets: "base/mockdata/mfl/"};var activeTextInstance = new ActiveText(options);});it("stops the iframes overlapping", function() {var iframeWidth = $(div.sample-1).find(div.iframe).width();var dpsWidth = $(div.sample-1).find(div.reader).width();expect(iframeWidth < dpsWidth).toBeTruthy();expect(iframeWidth).toBeCloseTo(dpsWidth / 2);});});
  14. 14. Functional testing/tests/utils.tests.jsdescribe("Functional tests for the utils class", function() {it(checks the output of getCorrectPathToAssetsFromHTMLPageAt, function(){var instance = new ActiveText.Loader({pathToAssets: "mockdata/exploringscience/"});var output = instance.test.getCorrectPathToAssetsFromHTMLPageAt("images/page0001Exploring_Science_AT_v1.pdf.png");expect(output).toBe("mockdata/exploringscience/images/");...});});
  15. 15. Specification testing/tests/specification.test.js$.ajaxSetup({async: false});$.mockjax({url: mockdata/sockosaurus/META-INF/container.xml,responseType: "xml",responseText: <?xml version="1.0" encoding="UTF-8"?><container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"><rootfiles><rootfile full-path="OPS/book.opf" media-type="application/oebps-package+xml"/></rootfiles></container>});describe("Data Loader test", function() {it("loads data", function() {activeTextInstance.loader.loadData();expect(activeTextInstance.data.getPath()).toBe("OPS/book.opf");});});
  16. 16. Edge-case testing/tests/edgecase.tests.jsdescribe("Navigation tests", function() {it("tests the edge cases", function() {activeTextInstance.navigation.gotoPage(5);expect(activeTextInstance.model.getCurrentPageNumber()).toBe(5);activeTextInstance.navigation.gotoPage(12);expect(activeTextInstance.model.getCurrentPageNumber()).toBe(12);activeTextInstance.navigation.gotoPage(-500);expect(activeTextInstance.model.getCurrentPageNumber()).toBe(0);activeTextInstance.navigation.gotoPage(500);expect(activeTextInstance.model.getCurrentPageNumber()).toBe(26);});});
  17. 17. ● describe(name, function)● it(name, function)● beforeEach(function) / afterEach(function)● expect(condition).toBe(value);● expect(condition).not.toBe(value);● .toEqual() / .toBeTruthy() / .toBeFalsy()● waitsFor(function) / runs(function)describe("A suite", function() {it("contains spec with an expectation", function() {expect(true).toBe(true);expect(true).not.toBe(false);});});Writing tests in Jasmine
  18. 18. Setup time
  19. 19. Python 2.7node.js + npmtestacularGrowl NotificationsPhantomJShttp://www.python.org/download/releases/http://nodejs.org/http://testacular.github.com/0.6.0/intro/installation.htmlhttp://www.growlforwindows.com/gfw/http://phantomjs.org/Installing Testacular + JasmineOptional Extras
  20. 20. > testacular init
  21. 21. Time to write some tests...
  22. 22. Time to write some code...
  23. 23. How many tests do you need?
  24. 24. // Testacular configuration// base path, that will be used to resolve files and excludebasePath = ;// list of files / patterns to load in the browserfiles = [JASMINE,JASMINE_ADAPTER,js/**/*.js,js-tests/**/*.js];// list of files to excludeexclude = [];preprocessors = {js/**/*.js : coverage};coverageReporter = {type: lcov,dir: coverage/};// test results reporter to use// possible values: dots, progress, junitreporters = [progress, coverage];// web server portport = 7654;Testacular configuration file + coverage// cli runner portrunnerPort = 9100;// enable / disable colors in the output (reporters and logs)colors = true;// level of logging// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN ||LOG_INFO || LOG_DEBUGlogLevel = LOG_INFO;// enable / disable watching file and executing tests whenever anyfile changesautoWatch = true;// Start these browsers, currently available:// - Chrome// - ChromeCanary// - Firefox// - Opera// - Safari (only Mac)// - PhantomJS// - IE (only Windows)browsers = [PhantomJS];// If browser does not capture in given timeout [ms], kill itcaptureTimeout = 60000;// Continuous Integration mode// if true, it capture browsers, run tests and exitsingleRun = false;
  25. 25. Thats all folks@psyked_james / aka James Ford