TEST DRIVEN DEVELOPMENT TIMOTHY BOLTON
Test Driven Development •What is TDD? •Why use TDD? •How to use TDD? •When to stray from TDD? •Super Simple Sample of TDD •Recap
What is TDD? •Development “driven” by testing. –Tests are written before code is. –Tests should initially fail –Production code should be enough to pass •A simple philosophy •A great way to make you feel superior
Why use TDD? •It makes refactoring very simple. •It gives you confidence •It helps create a scope of work •It creates a baseline •It helps you document your project •It helps bring new developers up to speed
How to use TDD? •There are 3 Rules 1.No production code unless it makes a failing test pass. 2.No more of a unit test written than is sufficient to make it fail. 3.No more production code is written than is sufficient to pass the one failing unit test.
How to use TDD cont’d •Build your own tools –My Environment consists of: •Vim •Tmux •watchTests.sh Script •Inotifywait
When to stray from TDD? •Ideally, “never” •Realistically? –Working on a pre-existing project –Working in a language where TDD frameworks are not established –When tests take too long. It’s the truth. :’(
Super Simple Sample of TDD •Email address availability with pure MivaScript and JavaScript •Remember –We don’t have a lot of time –We won’t write a lot of tests for MivaScript –We don’t have tools built for Mocking •https://bitbucket.org/snippets/timothybolton/BdL8
Super Simple Sample Cont’d •Where to start? –MivaScript •Create a simple “AssertTrue” function •Create a simple queryEmailTests.mv file –Put some lipstick on that pig with formatting –Write the first test •Create production code
Super Simple Sample Cont’d •What are we trying to accomplish? See if an email address is used already •Moving parts and external dependencies –Database Connection –Data in Database –Network Connection
Super Simple Sample Cont’d MivaScript “AssertEqual” function While we certainly don't need a function to do this, as we can make simple assertions with “MvIF” statements, it makes the code easier to read and communicates the intention. Other Assertions AssertTrue, AssertFalse, AssertNull, AssertNotNull AssertNotEqual, AssertIsDigit, AssertIsAlpha, etc. Be creative. Work together. Write better scripts.
Super Simple Sample Cont’d FILE NAME: mvassert.mv 1 <MIVA STANDARDOUTPUTLEVEL = "text, compresswhitespace"> 2 <MvFUNCTION NAME = "AssertEqual" PARAMETERS = "expected, actual" STANDARDOUTPUTLEVEL="" ERROROUTPUTLEVEL=""> 3 <MvFUNCTIONRETURN VALUE = "{ l.expected EQ l.actual }"> 4 </MvFUNCTION>
Super Simple Sample Cont’d FILE NAME: mvTestLibrary.mv 1 <MIVA STANDARDOUTPUTLEVEL = "html, compresswhitespace"> 2 3 <MvFUNCTION NAME = "generateTestResults" STANDARDOUTPUTLEVEL = "html, compresswhitespace"> 4 <MvEVAL EXPR = "{ buildViewStart() }"> 5 6 <MvFOR INDEX = "l.pos" FIRST = "{ 1 }" NEXT = "{ ++l.pos }" LAST = "{ g.currentTestNumber }"> 7 <MvASSIGN NAME = "l.currentTestStatusStyle" VALUE = "{ generateTestStatusStyle(g.testResults[l.pos]:status) }"> 8 <MvEVAL EXPR = "{ generateTestRowData(g.testResults[l.pos]:name, l.currentTestStatusStyle) }"> 9 </MvFOR> 10 <MvEVAL EXPR = "{ buildViewEnd() }"> 11 </MvFUNCTION> 12 13 <MvFUNCTION NAME = "generateTestRowData" PARAMETERS = "name, style" STANDARDOUTPUTLEVEL = "compresswhitespace"> 14 <MvIF EXPR = "{ g.source EQ 'curlVim' }"> 15 <MvASSIGN NAME = "l.view" VALUE = "{ generateTestRowDataCli(l.name, l.style) }"> 16 <MvELSE> 17 <MvASSIGN NAME = "l.view" VALUE = "{ generateTestRowDataHtml(l.name, l.style) }"> 18 </MvIF> 19 <MvFUNCTIONRETURN VALUE = "{ l.view }"> 20 </MvFUNCTION> 21 22 <MvFUNCTION NAME = "generateTestRowDataHtml" PARAMETERS = "name, style" STANDARDOUTPUTLEVEL = "compresswhitespace"> 23 <MvFUNCTIONRETURN VALUE = "{ '<tr><td>' $ l.style $ '</td><td>' $ l.name $ '()</td></tr>' }"> 24 </MvFUNCTION> 25 26 <MvFUNCTION NAME = "generateTestRowDataCli" PARAMETERS = "name, style" STANDARDOUTPUTLEVEL = "compresswhitespace"> 27 <MvFUNCTIONRETURN VALUE = "{ ' 28 ' $ l.style $ ' ' $ l.name $ '()' }"> 29 </MvFUNCTION> 30 31 <MvFUNCTION NAME = "buildViewEnd"> 32 <MvIF EXPR = "{ g.source EQ 'curlVim' }">
Super Simple Sample Cont’d FILENAME:queryEmailTests.mv 1 <MIVA STANDARDOUTPUTLEVEL = "text"> 2 <MvINCLUDE FILE = "mvassert.mv"> 3 <MvINCLUDE FILE = "mvTestLibrary.mv"> 4 <MvINCLUDE FILE = "queryEmailFunctions.mv"> 5 <MvASSIGN NAME = "g.currentTestNumber" VALUE = 0> 7 <MvCOMMENT>Tests are run here</MvCOMMENT> 8 <MvASSIGN NAME = "l.result" VALUE = "{ testEmailAvailableOnAddress() }"> 10 <MvEVAL EXPR = "{ generateTestResults() }"> 11 <MvEXIT> 13 <MvCOMMENT>Tests are written here</MvCOMMENT> 14 <MvFUNCTION NAME = "testEmailAvailableOnAddress" STANDARDOUTPUTLEVEL = "compresswhitespace"> 15 <MvASSIGN NAME = "g.currentTestNumber" VALUE = "{ ++g.currentTestNumber }"> 16 <MvASSIGN NAME = "g.testResults" MEMBER = "status" INDEX = "{ g.currentTestNumber }" VALUE = "{ AssertEqual(1, CheckEmailAvailable('jimmy@jon.net')) }"> 17 <MvASSIGN NAME = "g.testResults" MEMBER = "name" INDEX = "{ g.currentTestNumber }" VALUE = "{ 'testEmailAvailableOnAddress' }"> 18 </MvFUNCTION>
Super Simple Sample Cont’d Vim integration (put in your .vimrc, and validate for your sites) nnoremap <Leader>ca :! mvc % && curl -T %c ftp://ftp.mivamerchantdev.com/mm5/5.00/modules/util/ -u bolton.timothy@gmail.com@dts2639.mivamerchantdev.com:$MIVAPASSWORD && clear && curl http://dts2639.mivamerchantdev.com/mm5/5.00/modules/util/%c?Store_Code=MIVA_DEV&source=curlVim<CR>
Super Simple Sample Cont’d We have our first test, let's try to run it. What do you think will happen? That's right… it won't work. We need to write our production function.
Super Simple Sample Cont’d Boiler Plate Code FILENAME: queryEmailFunctions.mv 1 <MIVA STANDARDOUTPUTLEVEL = "text, compresswhitespace"> 2 <MvCOMMENT> 99% of this code is from the LSK or the fora.</MvCOMMENT> 3 <MvDO FILE = "../../lib/config.mvc"> 4 5 <MvIF EXPR = "{ NOT [ '../../lib/db.mvc' ].OpenDataFiles( g.Merchant_Version, g.Domain ) }"> 6 <MvEXIT> 7 </MvIF> 8 9 <MvEVAL EXPR = "{ [ '../../lib/util.mvc' ].SetRuntimePaths() }"> 10 11 <MvIF EXPR = "{ NOT [ g.Module_Library_DB ].Store_Open( g.Store_Code, g.Store ) }"> 12 <MvIF EXPR = "{ NOT g.Store_Code }"> <MvEVAL EXPR = "{ 'YOU NEED TO SUPPLY g.Store_Code' }"> </MvIF> 13 <MvEXIT> 14 </MvIF>
Super Simple Sample Cont’d 16 <MvFUNCTION NAME = "CheckEmailAvailable" PARAMETERS = "email" STANDARDOUTPUTLEVEL = "" ERROROUTPUTLEVEL = ""> 17 <MvOPENVIEW NAME = "Merchant" 18 VIEW = "Customers" 19 QUERY = "{ 'SELECT COUNT(*) AS emailUsed ' 20 $ 'FROM ' $ g.Store_Table_Prefix $ 'Customers ' 21 $ 'WHERE ' $ [ g.Module_Library_Native_DBAPI ].DB_Compare_UPPER( 'pw_email' ) 22 $ ' = ' 23 $ [ g.Module_Library_Native_DBAPI ].DB_Compare_UPPER( '?' ) }" 24 FIELDS = "l.email"> 25 <MvIF EXPR = "{ Customers.d.emailUsed GT 0 }"> 26 <MvASSIGN NAME = "l.returnValue" VALUE = "0"> 27 <MvELSE> 28 <MvASSIGN NAME = "l.returnValue" VALUE = "1"> 29 </MvIF> 30 <MvCLOSEVIEW NAME = "Merchant" VIEW = "Customers" > 31 <MvFUNCTIONRETURN VALUE = "{l.returnValue }"> 32 </MvFUNCTION>
Super Simple Sample Cont’d What happens when we run now? Using our Vim plugin, we can run from within our editor, from the CLI, or via the web. The mvTestFramework has detection from passed in parameters, to see the output we specify.
Super Simple Sample Cont’d Separation Separation function declarations from side-effects This make testing easier Our compiled script 1 <MIVA STANDARDOUTPUTLEVEL = "text, compresswhitespace"> 2 <MvINCLUDE FILE="queryEmailFunctions.mv"> 4 <MvEVAL EXPR = "{ CheckEmailAvailable(g.username) }"> 5 <MvEXIT>
Super Simple Sample Cont’d Test again. Now we can rinse and repeat with another test.
Super Simple Sample Cont’d JavaScript Testing Ajax can be difficult without mocking, or using synchronous calls. Which would then be “Jax”… because, there is no 'A'. This is depreciated because it degrades the user experience, but it can be useful for testing.
Super Simple Sample Cont’d Our simple assertion library will leverage some of the console behavior that comes with Chrome and other browsers. We will just create a simple tdd page that we can protect.
Super Simple Sample Cont’d 1 var testAjax = new XMLHttpRequest(); 2 3 testAjax.onreadystatechange = function() { 4 if(testAjax.readyState == 4 && testAjax.status == 200) { 5 return parseInt(testAjax.responseText); 6 } 7 } 8 9 function testAvailableEmail(email) { 10 testAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + email, false); 11 testAjax.send(); 12 return { "test": arguments.callee.name, 13 "actual": testAjax.responseText, 14 "expected": 1 15 }; 16 } 17 18 function testUnavailableEmail(email) { 19 testAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + email, false); 20 testAjax.send(); 21 return { "test": arguments.callee.name, 22 "actual": testAjax.responseText, 23 "expected": 0 24 }; 25 } 26 27 var testInformation = new Array(); 28 29 testInformation.push(testAvailableEmail('notused@example.com')); 30 testInformation.push(testUnavailableEmail('bolton.timothy@gmail.com')); 31 32 for(var i = 0; i < testInformation.length; i++) { 33 console.assert(testInformation[i].actual == testInformation[i].expected, testInformation[i].test + ' Failed. ' 34 + 'Actual: ' + testInformation[i].actual + '. Expected: ' + testInformation[i].expected ); 35 }
Super Simple Sample Cont’d 17 function testUnavailableEmail(email) { 18 testAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + email, false); 19 testAjax.send(); 20 return { "test": arguments.callee.name, 21 "actual": testAjax.responseText, 22 "expected": 0 }; 23 }
Super Simple Sample Cont’d 27 testInformation.push(testAvailableEmail('notused@example.com')); 28 testInformation.push(testUnavailableEmail('bolton.timothy@gmail.com')); 29 30 for(var i = 0; i < testInformation.length; i++) { 31 console.assert(testInformation[i].actual == testInformation[i].expected, 32 testInformation[i].test + ' Failed. ' 33 + 'Actual: ' + testInformation[i].actual + '. Expected: ' + testInformation[i].expected ); 34 }
Super Simple Sample Cont’d We are ready to put up some production code now.
Super Simple Sample Cont’d 1 var newAjax = new XMLHttpRequest(); 2 3 newAjax.onreadystatechange = function() { 4 if(newAjax.readyState == 4 && newAjax.status == 200) { 5 responseAction(newAjax.responseText); 6 } 7 } 8 9 var email = document.getElementById('Customer_LoginEmail'); 10 11 email.onchange = function() { 12 newAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + this.value); 13 newAjax.send(); 14 } 15 16 function responseAction(response) { 17 var alertText = ""; 18 if(parseInt(response) == 0) { 19 alertText = "That username is unavailable"; 20 } else { 21 alertText = "that username is available"; 22 } 23 alert(alertText); 24 }
Super Simple Sample Cont’d We are ready to put up some production code now. We have successfully test driven developed.
Exercises Refactor this to use JSON Add more tests Add more functionality
Parting Thoughts See the value in your tests now that they are reusable. It is annoying at first, but it pays off. Tests like this have small upkeep, and give you a lot of freedom to experiment. I hated TDD at first. Now, I think it's “okay”
Thank you!
TIMOTHY BOLTON

Test driven development (java script & mivascript)

  • 1.
  • 2.
    Test Driven Development •Whatis TDD? •Why use TDD? •How to use TDD? •When to stray from TDD? •Super Simple Sample of TDD •Recap
  • 3.
    What is TDD? •Development“driven” by testing. –Tests are written before code is. –Tests should initially fail –Production code should be enough to pass •A simple philosophy •A great way to make you feel superior
  • 4.
    Why use TDD? •Itmakes refactoring very simple. •It gives you confidence •It helps create a scope of work •It creates a baseline •It helps you document your project •It helps bring new developers up to speed
  • 5.
    How to useTDD? •There are 3 Rules 1.No production code unless it makes a failing test pass. 2.No more of a unit test written than is sufficient to make it fail. 3.No more production code is written than is sufficient to pass the one failing unit test.
  • 6.
    How to useTDD cont’d •Build your own tools –My Environment consists of: •Vim •Tmux •watchTests.sh Script •Inotifywait
  • 7.
    When to strayfrom TDD? •Ideally, “never” •Realistically? –Working on a pre-existing project –Working in a language where TDD frameworks are not established –When tests take too long. It’s the truth. :’(
  • 8.
    Super Simple Sampleof TDD •Email address availability with pure MivaScript and JavaScript •Remember –We don’t have a lot of time –We won’t write a lot of tests for MivaScript –We don’t have tools built for Mocking •https://bitbucket.org/snippets/timothybolton/BdL8
  • 9.
    Super Simple SampleCont’d •Where to start? –MivaScript •Create a simple “AssertTrue” function •Create a simple queryEmailTests.mv file –Put some lipstick on that pig with formatting –Write the first test •Create production code
  • 10.
    Super Simple SampleCont’d •What are we trying to accomplish? See if an email address is used already •Moving parts and external dependencies –Database Connection –Data in Database –Network Connection
  • 11.
    Super Simple SampleCont’d MivaScript “AssertEqual” function While we certainly don't need a function to do this, as we can make simple assertions with “MvIF” statements, it makes the code easier to read and communicates the intention. Other Assertions AssertTrue, AssertFalse, AssertNull, AssertNotNull AssertNotEqual, AssertIsDigit, AssertIsAlpha, etc. Be creative. Work together. Write better scripts.
  • 12.
    Super Simple SampleCont’d FILE NAME: mvassert.mv 1 <MIVA STANDARDOUTPUTLEVEL = "text, compresswhitespace"> 2 <MvFUNCTION NAME = "AssertEqual" PARAMETERS = "expected, actual" STANDARDOUTPUTLEVEL="" ERROROUTPUTLEVEL=""> 3 <MvFUNCTIONRETURN VALUE = "{ l.expected EQ l.actual }"> 4 </MvFUNCTION>
  • 13.
    Super Simple SampleCont’d FILE NAME: mvTestLibrary.mv 1 <MIVA STANDARDOUTPUTLEVEL = "html, compresswhitespace"> 2 3 <MvFUNCTION NAME = "generateTestResults" STANDARDOUTPUTLEVEL = "html, compresswhitespace"> 4 <MvEVAL EXPR = "{ buildViewStart() }"> 5 6 <MvFOR INDEX = "l.pos" FIRST = "{ 1 }" NEXT = "{ ++l.pos }" LAST = "{ g.currentTestNumber }"> 7 <MvASSIGN NAME = "l.currentTestStatusStyle" VALUE = "{ generateTestStatusStyle(g.testResults[l.pos]:status) }"> 8 <MvEVAL EXPR = "{ generateTestRowData(g.testResults[l.pos]:name, l.currentTestStatusStyle) }"> 9 </MvFOR> 10 <MvEVAL EXPR = "{ buildViewEnd() }"> 11 </MvFUNCTION> 12 13 <MvFUNCTION NAME = "generateTestRowData" PARAMETERS = "name, style" STANDARDOUTPUTLEVEL = "compresswhitespace"> 14 <MvIF EXPR = "{ g.source EQ 'curlVim' }"> 15 <MvASSIGN NAME = "l.view" VALUE = "{ generateTestRowDataCli(l.name, l.style) }"> 16 <MvELSE> 17 <MvASSIGN NAME = "l.view" VALUE = "{ generateTestRowDataHtml(l.name, l.style) }"> 18 </MvIF> 19 <MvFUNCTIONRETURN VALUE = "{ l.view }"> 20 </MvFUNCTION> 21 22 <MvFUNCTION NAME = "generateTestRowDataHtml" PARAMETERS = "name, style" STANDARDOUTPUTLEVEL = "compresswhitespace"> 23 <MvFUNCTIONRETURN VALUE = "{ '<tr><td>' $ l.style $ '</td><td>' $ l.name $ '()</td></tr>' }"> 24 </MvFUNCTION> 25 26 <MvFUNCTION NAME = "generateTestRowDataCli" PARAMETERS = "name, style" STANDARDOUTPUTLEVEL = "compresswhitespace"> 27 <MvFUNCTIONRETURN VALUE = "{ ' 28 ' $ l.style $ ' ' $ l.name $ '()' }"> 29 </MvFUNCTION> 30 31 <MvFUNCTION NAME = "buildViewEnd"> 32 <MvIF EXPR = "{ g.source EQ 'curlVim' }">
  • 14.
    Super Simple SampleCont’d FILENAME:queryEmailTests.mv 1 <MIVA STANDARDOUTPUTLEVEL = "text"> 2 <MvINCLUDE FILE = "mvassert.mv"> 3 <MvINCLUDE FILE = "mvTestLibrary.mv"> 4 <MvINCLUDE FILE = "queryEmailFunctions.mv"> 5 <MvASSIGN NAME = "g.currentTestNumber" VALUE = 0> 7 <MvCOMMENT>Tests are run here</MvCOMMENT> 8 <MvASSIGN NAME = "l.result" VALUE = "{ testEmailAvailableOnAddress() }"> 10 <MvEVAL EXPR = "{ generateTestResults() }"> 11 <MvEXIT> 13 <MvCOMMENT>Tests are written here</MvCOMMENT> 14 <MvFUNCTION NAME = "testEmailAvailableOnAddress" STANDARDOUTPUTLEVEL = "compresswhitespace"> 15 <MvASSIGN NAME = "g.currentTestNumber" VALUE = "{ ++g.currentTestNumber }"> 16 <MvASSIGN NAME = "g.testResults" MEMBER = "status" INDEX = "{ g.currentTestNumber }" VALUE = "{ AssertEqual(1, CheckEmailAvailable('jimmy@jon.net')) }"> 17 <MvASSIGN NAME = "g.testResults" MEMBER = "name" INDEX = "{ g.currentTestNumber }" VALUE = "{ 'testEmailAvailableOnAddress' }"> 18 </MvFUNCTION>
  • 15.
    Super Simple SampleCont’d Vim integration (put in your .vimrc, and validate for your sites) nnoremap <Leader>ca :! mvc % && curl -T %c ftp://ftp.mivamerchantdev.com/mm5/5.00/modules/util/ -u bolton.timothy@gmail.com@dts2639.mivamerchantdev.com:$MIVAPASSWORD && clear && curl http://dts2639.mivamerchantdev.com/mm5/5.00/modules/util/%c?Store_Code=MIVA_DEV&source=curlVim<CR>
  • 16.
    Super Simple SampleCont’d We have our first test, let's try to run it. What do you think will happen? That's right… it won't work. We need to write our production function.
  • 17.
    Super Simple SampleCont’d Boiler Plate Code FILENAME: queryEmailFunctions.mv 1 <MIVA STANDARDOUTPUTLEVEL = "text, compresswhitespace"> 2 <MvCOMMENT> 99% of this code is from the LSK or the fora.</MvCOMMENT> 3 <MvDO FILE = "../../lib/config.mvc"> 4 5 <MvIF EXPR = "{ NOT [ '../../lib/db.mvc' ].OpenDataFiles( g.Merchant_Version, g.Domain ) }"> 6 <MvEXIT> 7 </MvIF> 8 9 <MvEVAL EXPR = "{ [ '../../lib/util.mvc' ].SetRuntimePaths() }"> 10 11 <MvIF EXPR = "{ NOT [ g.Module_Library_DB ].Store_Open( g.Store_Code, g.Store ) }"> 12 <MvIF EXPR = "{ NOT g.Store_Code }"> <MvEVAL EXPR = "{ 'YOU NEED TO SUPPLY g.Store_Code' }"> </MvIF> 13 <MvEXIT> 14 </MvIF>
  • 18.
    Super Simple SampleCont’d 16 <MvFUNCTION NAME = "CheckEmailAvailable" PARAMETERS = "email" STANDARDOUTPUTLEVEL = "" ERROROUTPUTLEVEL = ""> 17 <MvOPENVIEW NAME = "Merchant" 18 VIEW = "Customers" 19 QUERY = "{ 'SELECT COUNT(*) AS emailUsed ' 20 $ 'FROM ' $ g.Store_Table_Prefix $ 'Customers ' 21 $ 'WHERE ' $ [ g.Module_Library_Native_DBAPI ].DB_Compare_UPPER( 'pw_email' ) 22 $ ' = ' 23 $ [ g.Module_Library_Native_DBAPI ].DB_Compare_UPPER( '?' ) }" 24 FIELDS = "l.email"> 25 <MvIF EXPR = "{ Customers.d.emailUsed GT 0 }"> 26 <MvASSIGN NAME = "l.returnValue" VALUE = "0"> 27 <MvELSE> 28 <MvASSIGN NAME = "l.returnValue" VALUE = "1"> 29 </MvIF> 30 <MvCLOSEVIEW NAME = "Merchant" VIEW = "Customers" > 31 <MvFUNCTIONRETURN VALUE = "{l.returnValue }"> 32 </MvFUNCTION>
  • 19.
    Super Simple SampleCont’d What happens when we run now? Using our Vim plugin, we can run from within our editor, from the CLI, or via the web. The mvTestFramework has detection from passed in parameters, to see the output we specify.
  • 20.
    Super Simple SampleCont’d Separation Separation function declarations from side-effects This make testing easier Our compiled script 1 <MIVA STANDARDOUTPUTLEVEL = "text, compresswhitespace"> 2 <MvINCLUDE FILE="queryEmailFunctions.mv"> 4 <MvEVAL EXPR = "{ CheckEmailAvailable(g.username) }"> 5 <MvEXIT>
  • 21.
    Super Simple SampleCont’d Test again. Now we can rinse and repeat with another test.
  • 22.
    Super Simple SampleCont’d JavaScript Testing Ajax can be difficult without mocking, or using synchronous calls. Which would then be “Jax”… because, there is no 'A'. This is depreciated because it degrades the user experience, but it can be useful for testing.
  • 23.
    Super Simple SampleCont’d Our simple assertion library will leverage some of the console behavior that comes with Chrome and other browsers. We will just create a simple tdd page that we can protect.
  • 24.
    Super Simple SampleCont’d 1 var testAjax = new XMLHttpRequest(); 2 3 testAjax.onreadystatechange = function() { 4 if(testAjax.readyState == 4 && testAjax.status == 200) { 5 return parseInt(testAjax.responseText); 6 } 7 } 8 9 function testAvailableEmail(email) { 10 testAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + email, false); 11 testAjax.send(); 12 return { "test": arguments.callee.name, 13 "actual": testAjax.responseText, 14 "expected": 1 15 }; 16 } 17 18 function testUnavailableEmail(email) { 19 testAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + email, false); 20 testAjax.send(); 21 return { "test": arguments.callee.name, 22 "actual": testAjax.responseText, 23 "expected": 0 24 }; 25 } 26 27 var testInformation = new Array(); 28 29 testInformation.push(testAvailableEmail('notused@example.com')); 30 testInformation.push(testUnavailableEmail('bolton.timothy@gmail.com')); 31 32 for(var i = 0; i < testInformation.length; i++) { 33 console.assert(testInformation[i].actual == testInformation[i].expected, testInformation[i].test + ' Failed. ' 34 + 'Actual: ' + testInformation[i].actual + '. Expected: ' + testInformation[i].expected ); 35 }
  • 25.
    Super Simple SampleCont’d 17 function testUnavailableEmail(email) { 18 testAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + email, false); 19 testAjax.send(); 20 return { "test": arguments.callee.name, 21 "actual": testAjax.responseText, 22 "expected": 0 }; 23 }
  • 26.
    Super Simple SampleCont’d 27 testInformation.push(testAvailableEmail('notused@example.com')); 28 testInformation.push(testUnavailableEmail('bolton.timothy@gmail.com')); 29 30 for(var i = 0; i < testInformation.length; i++) { 31 console.assert(testInformation[i].actual == testInformation[i].expected, 32 testInformation[i].test + ' Failed. ' 33 + 'Actual: ' + testInformation[i].actual + '. Expected: ' + testInformation[i].expected ); 34 }
  • 27.
    Super Simple SampleCont’d We are ready to put up some production code now.
  • 28.
    Super Simple SampleCont’d 1 var newAjax = new XMLHttpRequest(); 2 3 newAjax.onreadystatechange = function() { 4 if(newAjax.readyState == 4 && newAjax.status == 200) { 5 responseAction(newAjax.responseText); 6 } 7 } 8 9 var email = document.getElementById('Customer_LoginEmail'); 10 11 email.onchange = function() { 12 newAjax.open("GET", "5.00/modules/util/queryEmail.mvc?store_code=MIVA_DEV&username=" + this.value); 13 newAjax.send(); 14 } 15 16 function responseAction(response) { 17 var alertText = ""; 18 if(parseInt(response) == 0) { 19 alertText = "That username is unavailable"; 20 } else { 21 alertText = "that username is available"; 22 } 23 alert(alertText); 24 }
  • 29.
    Super Simple SampleCont’d We are ready to put up some production code now. We have successfully test driven developed.
  • 30.
    Exercises Refactor this touse JSON Add more tests Add more functionality
  • 31.
    Parting Thoughts See thevalue in your tests now that they are reusable. It is annoying at first, but it pays off. Tests like this have small upkeep, and give you a lot of freedom to experiment. I hated TDD at first. Now, I think it's “okay”
  • 32.
  • 33.