Presentation is loading. Please wait.

Presentation is loading. Please wait.

* Who Am I? * State of the Room? * CF API * Ways to test your API? * Overview of Testing Tools * Using Testing in your Workflow * Installing Jasmine *

Similar presentations


Presentation on theme: "* Who Am I? * State of the Room? * CF API * Ways to test your API? * Overview of Testing Tools * Using Testing in your Workflow * Installing Jasmine *"— Presentation transcript:

1

2 * Who Am I? * State of the Room? * CF API * Ways to test your API? * Overview of Testing Tools * Using Testing in your Workflow * Installing Jasmine * Installing Testbox * Live Demo

3 * Gavin Pickin – developing Web Apps since late 90s * New Addition to Ortus Solutions * ContentBox Evangelist * What else do you need to know? * Blog - http://www.gpickin.comhttp://www.gpickin.com * Twitter – http://twitter.com/gpickinhttp://twitter.com/gpickin * Github - https://github.com/gpickinhttps://github.com/gpickin * Lets get on with the show.

4 * A few questions for you guys * If you have arms, use them.

5 * Most CF Apps are moving towards providing an API for multiple consumers * CF has many REST API Solutions and even more with CF 12 coming soon * Built in CF * Built in Railo/Lucee * Coldbox API * Taffy

6 * Click around in the browser yourself * Setup Selenium / Web Driver to click around for you * Structured Programmatic Tests

7 * Black/White Box * Unit Testing * Integration Testing * Functional Tests * System Tests * End to End Tests * Sanity Testing * Regression Test * Acceptance Tests * Load Testing * Stress Test * Performance Tests * Usability Tests * + More

8

9 * Integration Tests several of the pieces together * Most of the types of tests are variations of an Integration Test * Can include mocks but can full end to end tests including DB / APIs

10 “unit testing is a software verification and validation method in which a programmer tests if individual units of source code are fit for use. A unit is the smallest testable part of an application” - wikipedia

11 * Can improve code quality -> quick error discovery * Code confidence via immediate verification * Can expose high coupling * Will encourage refactoring to produce > testable code * Remember: Testing is all about behavior and expectations

12 * TDD = Test Driven Development * Write Tests * Run them and they Fail * Write Functions to Fulfill the Tests * Tests should pass * Refactor in confidence * Test focus on Functionality

13 * BDD = Behavior Driven Development Actually similar to TDD except: * Focuses on Behavior and Specifications * Specs (tests) are fluent and readable * Readability makes them great for all levels of testing in the organization * Hard to find TDD examples in JS that are not using BDD describe and it blocks

14 Test( ‘Email address must not be blank’, function(){ notEqual(email, “”, "failed"); });

15 Describe( ‘Email Address’, function(){ It(‘should not be blank’, function(){ expect(email).not.toBe(“”); });

16 expect(true).toBe(true);

17 expect(true).not.toBe(true);

18 expect(true).toBe(true); expect(a).not.toBe(null); expect(a).toEqual(12); expect(message).toMatch(/bar/); expect(message).toMatch("bar"); expect(message).not.toMatch(/quux/); expect(a.foo).toBeDefined(); expect(a.bar).not.toBeDefined();

19 NodeJS - CLI In the Browser

20 * MxUnit was the standard * TestBox is the new standard * Other options

21 TestBox is a next generation testing framework for ColdFusion (CFML) that is based on BDD (Behavior Driven Development) for providing a clean obvious syntax for writing tests. It contains not only a testing framework, runner, assertions and expectations library but also ships with MockBox, A Mocking & Stubbing Framework,. It also supports xUnit style of testing and MXUnit compatibilities.

22 function testHelloWorld(){ $assert.includes( helloWorld(), ”world" ); }

23 describe("Hello world function", function() { it(”contains the word world", function() { expect(helloWorld()).toContain("world"); });

24 feature( "Box Size", function(){ describe( "In order to know what size box I need As a distribution manager I want to know the volume of the box", function(){ scenario( "Get box volume", function(){ given( "I have entered a width of 20 And a height of 30 And a depth of 40", function(){ when( "I run the calculation", function(){ then( "the result should be 24000", function(){ // call the method with the arguments and test the outcome expect( myObject.myFunction(20,30,40) ).toBe( 24000 ); });

25 * There are a few choices

26 * Jasmine, Mocha and QUnit

27 * Jasmine comes ready to go out of the box * Fluent Syntax – BDD Style * Includes lots of matchers * Has spies included * Very popular, lots of support * Angular uses Jasmine with Karma (CLI) * Headless running and plays well with CI servers

28 * Async testing in 1.3 can be a headache * Async testing in 2.0 is hard to find blog posts on (I need to write one) * Expects *spec.js suffix for test files * This can be modified depending on how you are running the tests

29 describe("Hello world function", function() { it(”contains the word world", function() { expect(helloWorld()).toContain("world"); });

30 * Simple Setup * Simple Async testing * Works great with other Assertion libraries like Chai ( not included ) * Solid Support with CI Servers, with Plugins for others * Opinion says Mocha blazing the trail for new features

31 * Requires other Libraries for key features * No Assertion Library included * No Mocking / Spied included * Need to create the runner manually * Newer to the game so not as popular or supported as others but gaining traction.

32 var expect = require('chai').expect; describe(’Hello World Function', function(){ it('should contain the word world', function(){ expect(helloWorld()).to.contain(’world'); })

33 * The oldest of the main testing frameworks * Is popular due to use in jQuery and age * Ember’s default Unit testing Framework

34 * Development slowed down since 2013 (but still under development) * Syntax – No BDD style * Assertion libraries – limited matchers

35 QUnit.test( "ok test", function( assert ) { assert.ok( true, "true succeeds" ); assert.ok( "non-empty", "non-empty string succeeds" ); assert.ok( false, "false fails" ); assert.ok( 0, "0 fails" ); assert.ok( NaN, "NaN fails" ); assert.ok( "", "empty string fails" ); assert.ok( null, "null fails" ); assert.ok( undefined, "undefined fails" ); });

36 Photo Credit – Kombination http://www.kombination.co.za/wp-content/uploads/2012/10/baby_w_spaghetti_mess_4987941.jpg

37

38

39 * Things to refactor to make your code testable * Code should not be one big chunk of Javascript in onReady() * Deep nested callbacks & Anon functions cannot easily be singled out and tested * Remove Tight Coupling – DOM access for example

40 * Lets look at some code * This isn’t BEST PRACTICE, its BETTER PRACTICE than you were doing * Its not really refactoring if you don’t have tests, its “moving code and asking for trouble” Kev McCabe

41 var personObjLit = { ssn: ’xxxxxxxx', age: '35', name: 'Gavin Pickin', getAge: function(){ return this.age; }, getName: function() { return this.name; } };

42 var personObjLit2 = function() { ssn = ’xxxxxxx'; age = '35'; name = 'Gavin Pickin’; return { getAge: function(){ return age; }, getName: function() { return name; } };

43 * Using HTML Test Runners * Keep a Browser open * F5 refresh tests

44 * Run Jasmine – manual * Run tests at the end of each section of work * Run Grunt-Watch – automatic * Runs Jasmine on every file change * Grunt can run other tasks as well, minification etc

45 * Browser Views * Eclipse allows you to open files in web view – uses HTML Runner * Run Jasmine / Grunt / Karma in IDE Console * Fairly Easy to setup * See Demo– Sublime Text 2 (if we have time)

46 * Install / Run Jasmine Standalone for Browser * Install / Run Jasmine with NodeJs * Install / Run Jasmine with Grunt Watch * Install / Run Testbox in Browser * Install / Run Testbox with Grunt Watch * Install / Run Grunt Watch inside Sublime Text 2

47 Download standalone package from Github (I have 2.1.3) https://github.com/jasmine/jasmine/tree/master/dist Unzip into your /tests folder Run /tests/SpecRunner.html to see example tests

48

49 http://www.testableapi.local.com:8504/tests/SpecRunner.html

50 Jasmine Spec Runner v2.1.3

51 Assuming you have NodeJs Installed… install Jasmine $ npm install jasmine jasmine@2.2.1 node_modules/jasmine ├── exit@0.1.2 ├── jasmine-core@2.2.0 └── glob@3.2.11 (inherits@2.0.1, minimatch@0.3.0)

52 Once Jasmine is installed in your project $ Jasmine init

53 Edit Jasmine.json to update Locations for Spec Files and Helper Files { "spec_dir": "spec", "spec_files": [ "**/*[sS]pec.js" ], "helpers": [ "helpers/**/*.js" ] }

54 $ Jasmine Started F Failures: 1) A suite contains spec with an expectation Message: Expected true to be false. Stack: Error: Expected true to be false. at Object. (/Users/gavinpickin/Dropbox/Apps/testApp/www/spec/test_spec.js:3 :18) 1 spec, 1 failure Finished in 0.009 seconds

55 * Jasmine-Node is great for Node * Jasmine Node doesn’t have a headless browser * Hard to test Browser code * So what should I use?

56 * Install Grunt npm install grunt * Install Grunt – Jasmine npm install grunt-contrib-jasmine * Install Grunt – Watch npm install grunt-contrib-watch * Note: On Mac, I also needed to install Grunt CLI npm install –g grunt-cli

57 // gruntfile.js - https://gist.github.com/gpickin/1e1e7902d1d3676d23c5 module.exports = function (grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('node_modules/grunt/package.json'), jasmine: { all: { src: ['js/*.js' ], options: { //'vendor': ['path/to/vendor/libs/*.js'], 'specs': ['specs/*.js' ], '--web-security': false } },

58 // gruntfile.js part 2 watch: { js: { files: [ 'js/*.js', 'specs/*.js', ], tasks: ['jasmine:all'] } });

59 // gruntfile.js part 3 grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch'); };

60 describe("Forgotten Password Form", function() { it("should warn you if the email is invalid before making Ajax Call", function() { expect( isEmailInputInvalid('') ).toBe(true); expect( isEmailInputInvalid('dddddddddd') ).toBe(true); expect( isEmailInputInvalid('dddddd@') ).toBe(true); expect( isEmailInputInvalid('dddddd@ddddd') ).toBe(true); expect( isEmailInputInvalid('dddddd@ddddddd.') ).toBe(true); expect( isEmailInputInvalid('dddddd@ddddddd.com') ).toBe(false); });

61 describe("Login Form", function() { it("should set status correct status message with successful Ajax Response", function() { spyOn( window, "setStatusMessage"); processLoginAjaxDone('{"RESULT":"200"}'); expect(setStatusMessage).toHaveBeenCalled(); expect(setStatusMessage).toHaveBeenCalledWith( ‘TARDIS Access Granted - Please wait for the Doctor to take you for a spin'); });

62 describe("Login API", function() { it("should return a failing Ajax Response", function() { spyOn( window, "processLoginAjaxDone"); loginButtonEventHandlerProcess( 'gavin@gavin.co.nz', 'password'); expect(processLoginAjaxDone).toHaveBeenCalled(); expect(processLoginAjaxDone).toHaveBeenCalledWith( ‘{"RESULT":400}'); expect(processLoginAjaxFail).not.toHaveBeenCalled(); });

63 describe("Login API", function() { it("should return a failing Ajax Response", function() { spyOn( window, "processLoginAjaxDone"); loginButtonEventHandlerProcess( 'gavin@gavin.co.nz', 'password'); expect(processLoginAjaxDone).toHaveBeenCalled(); expect(processLoginAjaxDone).toHaveBeenCalledWith( ‘{"RESULT":400}'); expect(processLoginAjaxFail).not.toHaveBeenCalled(); });

64 * You want Unit Tests to test the unit and not it’s dependencies * You want Unit Tests to run quick * You should mock the API in the Ajax call * But we want to test the API * So essentially, we’re writing an integration test.

65 describe("Login API", function() { beforeEach(function( done ) { spyOn( window, "processLoginAjaxDone").and.callFake( function(){ done(); }); spyOn( window, "processLoginAjaxFail").and.callFake( function(){ done(); }); loginButtonEventHandlerProcess('gavin@gavin.co.nz', 'password'); }); it("should return a failing Ajax Response", function() { }); });

66 describe("Login API", function() { beforeEach(function( done ) { … }); it("should return a failing Ajax Response", function() { expect(processLoginAjaxDone).toHaveBeenCalled(); expect(processLoginAjaxDone).toHaveBeenCalledWith( '{"RESULT":400}'); expect(processLoginAjaxFail).not.toHaveBeenCalled(); });

67

68

69 * Install Testbox – Thanks to Commandbox * box install testbox * Decide how you want to run Testbox

70 *

71 // tests/specs/CFCTest.cfc component extends="testbox.system.BaseSpec" { function run() { it( "will error with incorrect login", function(){ var oTest = new cfcs.userServiceRemote(); expect( oTest.login( 'gavin@gavin.com', 'topsecret').result ).toBe('400'); }); }

72 // tests/specs/APITest.cfc component extends="testbox.system.BaseSpec" { function run() { describe("userService API Login", function(){ it( "will error with incorrect login", function(){ var email = "gavin@gavin.com"; var password = "topsecret”; var result = ""; http url="http://www.testableapi.local.com:8504/cfcs/userServiceRemote.cfc?metho d=login&email=#email#&password=#password#" result="result”; expect( DeserializeJSON(result.filecontent).result ).toBe('400'); }); }

73 * Install Testbox Runner – Thanks Sean Coyne * npm install testbox-runner * Install Grunt Shell * npm install grunt-shell * Add Grunt Configuration

74 * Install Testbox Runner – Thanks Sean Coyne * npm install testbox-runner * Install Grunt Shell * npm install grunt-shell * Add Grunt Configuration

75 module.exports = function (grunt) { grunt.loadNpmTasks('grunt-shell'); grunt.initConfig({ … }) }

76 Watch: { … cfml: { files: [ "cfcs/*.cfc"], tasks: [ "testbox" ] }

77 shell: { testbox: { command: "./node_modules/testbox- runner/index.js --colors --runner http://www.testableapi.local.com:8504/tests/r unner.cfm --directory /tests/specs --recurse true” }

78 grunt.registerTask("testbox", [ "shell:testbox" ]); grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch');

79 js: { files: [ 'js/*.js', 'specs/*.js', "cfcs/*.cfc” ], tasks: ['jasmine:all'] },

80 Jasmine https://gist.github.com/gpickin/1e1e7902d1d3 676d23c5 Jasmine + Testbox https://gist.github.com/gpickin/9fc82df3667ee b63c7e7

81

82 * Testbox has several runners, you have seen the HTML one, this Runner uses the JSON runner and then formats it. * http://www.testableapi.local.com:8504/tests/run ner.cfm?reporter=JSON&directory=%2Ftests%2Fspec s&recurse=true http://www.testableapi.local.com:8504/tests/run ner.cfm?reporter=JSON&directory=%2Ftests%2Fspec s&recurse=true

83 * Install PackageControl into Sublime Text * Install Grunt from PackageControl * https://packagecontrol.io/packages/Grunt https://packagecontrol.io/packages/Grunt * Update Grunt Sublime Settings for paths { "exec_args": { "path": "/bin:/usr/bin:/usr/local/bin” } } * Then Command Shift P – grunt

84

85 * Any questions? * Interesting Link: https://medium.com/@Zyklus/beautiful-seamless- javascript-testing-in-10-minutes-2a743637035b

86 https://www.ortussolutions.com/odw FREE ONLINE


Download ppt "* Who Am I? * State of the Room? * CF API * Ways to test your API? * Overview of Testing Tools * Using Testing in your Workflow * Installing Jasmine *"

Similar presentations


Ads by Google