The Cache: Technology Expert's Forum
 
*
Welcome, Guest. Please login or register. September 18, 2019, 07:42:55 PM

Login with username, password and session length


Pages: [1]
  Print  
Author Topic: Test-driven development basics  (Read 4628 times)
isthisthingon
Global Moderator
Lifer
*****
Offline Offline

Posts: 2879



View Profile
« on: May 19, 2009, 10:10:47 PM »

Test-driven development (TDD) is a software development technique that uses short development iterations based on pre-written test cases that define desired improvements or new functions. Each iteration produces code necessary to pass that iteration's tests. Finally, the programmer or team refactors the code to accommodate changes. A key TDD concept is that preparing tests before coding facilitates rapid feedback changes. Note that test-driven development is a software design method, not merely a method of testing.  Test-Driven Development is related to the test-first programming concepts of Extreme Programming, begun in 1999, but more recently is creating more general interest in its own right.  Programmers also apply the concept to improving and debugging legacy code developed with older techniques.” - Wikipedia (http://en.wikipedia.org/wiki/Test-driven_development)

"Testing is the key to successful long term development. Salesforce.com strongly recommends that you use a test-driven development process, that is, development that occurs at the same time as code development." - Apex Language Reference

I'm sure many of you are familiar with test-driven development.  This thread is intended to be a primer for those who may not have experience with it.  In the most basic sense, test-driven development involves the automation of code execution in parallel with the development of the code providing the functionality desired.  In other words, code is written to call application code and verify the results.  This happens alongside software development and should occur during if not before the software is developed. 

Here's an example from an HTTP callout class I wrote.  The code details are not important but the automated execution in the test class that follows is:

Code:
public class HTTPManager
{
// Class vars
public String var1, var2, var3, etc., etc.

public HTTPManager()
{
// Constructor code removed
}

public HTTPManager(String credName)
{
// Overloaded constructor
if(credName == 'TestMethod')
{
isTest = true;
}
}

private void fc(Credentials__c cc)
{
if(cc != null)
{
APIPassword = cc.APIPassword__c;
SiteId = cc.SiteId__c;
EmailServer = cc.EmailServer__c;
MasterListId = cc.MasterListId__c;
InputHeader = '<SITE_ID>' + SiteId + '</SITE_ID>' +
'<MLID>' +  MasterListId + '</MLID>' +
'<DATA type="extra" id="password">' + APIPassword + '</DATA>';
}
// Else no credentials in org
}

public HttpResponse HTTPRequest(Request lr)
{
HTTPResponse RetVal;
HTTPRequest req = new HttpRequest();
String endpoint, body;

endpoint =  EmailServer + '/mailing_list.html?type=' + lr. Type + '&activity=' + lr. Activity;
body = 'input=<DATASET>' + InputHeader;
for(String inp : lr.Input)
{
body += inp;
}
body += '</DATASET>';

// For display or exception information
Endpoint = endpoint;
Body = body;
Method = lr.HTTPMethod;

// Make the HTTP callout
req.setEndpoint(endpoint);
req.setBody(body);
req.setMethod(lr.HTTPMethod);
HTTP http = new HTTP();
if(!isTest)
RetVal = http.send(req);

return RetVal;
}

public List< ResponseRecord>  APIParse(String xml, String funcType, String funcActivity)
{
XmlStreamReader reader = new XmlStreamReader(xml);
List< ResponseRecord>  rr = new List< ResponseRecord>();

String currentElementName;
String eventType;
Boolean isInRecord = false;
Boolean initPass = true;
String currentName = '';
String currentEvent = '';
ResponseRecord rr;

if(funcType == 'demographic' && funcActivity == 'query-enabled')
{
XMLDom dom = new XMLDom(xml);
XMLDom.Element element = new XMLDom.Element();
List<XMLDom.Element> records = dom.getElementsByTagName('RECORD');

for(XMLDom.Element r : records)
{
rr = new  ResponseRecord();
List<XMLDom.Element> e = r.childNodes;

system.debug('SYSTEM.DEBUG---------->');
system.debug('SYSTEM.DEBUG----------> BEGIN RECORD');
system.debug('SYSTEM.DEBUG---------->');

Integer i = 0;
for(XMLDom.Element ee : e)
{
List<String> aValues = ee.attributes.values();
system.debug('SYSTEM.DEBUG----------> NODE NAME: ' + aValues[0]);
system.debug('SYSTEM.DEBUG----------> NODE VALUE: ' + ee.nodeValue);


if(aValues[0] == 'name')
{
rr. Name = ee.nodeValue;
}
else if(aValues[0] == 'id')
{
rr. Id = ee.nodeValue;
}
else if(aValues[0] == 'type')
{
rr. Type = ee.nodeValue;
}
}

rr.add(rr);
system.debug('SYSTEM.DEBUG---------->');
system.debug('SYSTEM.DEBUG----------> END RECORD');
system.debug('SYSTEM.DEBUG---------->');
}
}

return  rr;
}
}


The key elements of test driven development are entry points and branch logic.  Calling all functions is a good start but all logic must be tested too.  Therefore all conditional logic must be primed and tested via the test code.  The goal is to execute 100% of your code via test classes or test functions.  Here's the test class I wrote yesterday that accomplishes this (some info changed for obvious reasons):

Code:
public class HTTPManager_Test
{
public static testMethod void HTTPManager_Test()
    {
Credentials__c c = new Credentials__c(Name = 'TestMethod', APIPassword__c = 'password', SiteId__c = '666333', EmailServer__c = 'https://www.FFF.com/API', MasterListId__c = '333');
insert c;

HTTPManager hm = new HTTPManager('TestMethod');
HTTPManager.Request lr = new HTTPManager.Request();
lr.HTTPMethod = 'POST';
lr.Type = 'record';
lr.Activity = 'query-listdata';
lr.Input = new List<String>();
lr.Input.add('<DATA type="extra" id="type">active</DATA>');

HttpResponse hr = hm.HTTPRequest(lr);
String xml = '<DATASET ><TYPE >success</TYPE><RECORD ><DATA type=\'name\' >EMAIL_ADDRESS</DATA>;
hm.APIParse(xml, 'demographic', 'query-enabled');

hm = new HTTPManager();
    }
}

The above example instantiates the HTTPManager class and populates it with various data to ensure that all lines of code are executed.  You'll notice that I call it again at the end with no parameters causing the overloaded constructor to fire. 

The Force.com platform supports test-driven development and it's included in the Eclipse plug-in.  You simply right-click on your test class and select “Force.com | Run tests.”  Test-driven development is no guarantee that all bugs will be discovered prior to release.  However, with these automated processes in place, you're far more likely to identify problems without relying on unit and regression tests.  When functionality is added to an existing application you can easily identify any potential issues with legacy code by re-running these tests to verify that nothing was broken.

At first this may seem cumbersome and even unnecessary.  But it improves code manageability on so many levels that I'll never return to coding without it.   
Logged

I would love to change the world, but they won't give me the source code.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #1 on: May 19, 2009, 10:58:56 PM »

interesting.

Of all the programming styles, pragmatic/tdd/fdd/iterative/agile/waterfall/etc I find I land closest to an iterative-FDD, which is a bit less structured than TDD. Though in the end, I probably land in Chaotic WTF Dammit style.

Your right, it does seem cumbersome. I of course see the value, especially on a project that could cost you your house and first born if you screw it up. I had looked into TDD or a more strict FDD, and while doing so, i came up with an idea. One problem with TDD is that you can only test the cases you actually think of, or at least the cases you are designing for. In a web environment however, I have learned time and again that if there is a problem, the public will find it, every single time. I started to wonder if you could crowd-source the test cycles and be significantly more effective at finding weaknesses in the code. So i have lately been looking into Amazon Turk.

I of course realize that the turk makes more sense for more completed projects, where as TDD tests the smallest slices possible. I just have never been able to wrap my brain around the benefit in my work.

I have done a TDD like spider for finding XSS and sql-injection issues in my projects, which of course I already had due to less legitimate endeavors... It ran primary and secondary exploits and because it attached to the database, it could simulate successful column/table guesses. Technically I think it falls outside the strict definition of TDD since it is testing many things at once not just the slice.
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
vsloathe
vim ftw!
Global Moderator
Lifer
*****
Offline Offline

Posts: 1669



View Profile
« Reply #2 on: May 20, 2009, 11:40:52 AM »

I'm a RAD boi
Logged

hai
isthisthingon
Global Moderator
Lifer
*****
Offline Offline

Posts: 2879



View Profile
« Reply #3 on: May 20, 2009, 12:05:35 PM »

The waterfall can smoke me  Mobster

Quote
Test-Driven Development is related to the test-first programming concepts of Extreme Programming

Logged

I would love to change the world, but they won't give me the source code.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #4 on: May 20, 2009, 12:34:45 PM »

i couldnt do pure waterfall, because I never produce good code the first pass through. LOL
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
isthisthingon
Global Moderator
Lifer
*****
Offline Offline

Posts: 2879



View Profile
« Reply #5 on: May 20, 2009, 01:08:27 PM »

I swore off the waterfall approach 17 years ago when I left Oracle.  There's nothing more painful than reporting to a massive gantt chart.  Back then I referred to RAD as iterative software development.  Here's one of my faves (from IID, a Brief History - http://www2.umassd.edu/SWPI/xp/articles/r6047.pdf):

Quote
"In a personal communication, Walker Royce, his son and a contributor to popular IID methods in the 1990s, said this of his father and the paper: 'He was always a proponent of iterative, incremental, evolutionary development. His paper described the waterfall as the simplest description, but that it would not work for all but the most straightforward projects.'”

 D'oh!
Logged

I would love to change the world, but they won't give me the source code.
vsloathe
vim ftw!
Global Moderator
Lifer
*****
Offline Offline

Posts: 1669



View Profile
« Reply #6 on: May 20, 2009, 01:21:57 PM »

Every project is straightfoward though if you approach it the right way.

 Grin
Logged

hai
isthisthingon
Global Moderator
Lifer
*****
Offline Offline

Posts: 2879



View Profile
« Reply #7 on: May 20, 2009, 01:31:41 PM »

Tell that to Raytheon Wink
Logged

I would love to change the world, but they won't give me the source code.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #8 on: May 20, 2009, 01:57:00 PM »

lol
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
isthisthingon
Global Moderator
Lifer
*****
Offline Offline

Posts: 2879



View Profile
« Reply #9 on: May 20, 2009, 06:24:29 PM »

Quote
One problem with TDD is that you can only test the cases you actually think of, or at least the cases you are designing for.

Very true.

Quote
In a web environment however, I have learned time and again that if there is a problem, the public will find it, every single time. I started to wonder if you could crowd-source the test cycles and be significantly more effective at finding weaknesses in the code.

TDD for certain aspects of web development can be seriously challenging to implement.  Personally I stick to server-side TDD. The crowd-source approach sounds promising, assuming it's large enough.  I think a demographically diverse pool of testers would be ideal.  Works for Microsoft  Devilish

Quote
I have done a TDD like spider for finding XSS and sql-injection issues in my projects, which of course I already had due to less legitimate endeavors... It ran primary and secondary exploits and because it attached to the database, it could simulate successful column/table guesses. Technically I think it falls outside the strict definition of TDD since it is testing many things at once not just the slice.

Strict definitions aside, I think what you're doing with sql-injection testing sounds way cool.
Logged

I would love to change the world, but they won't give me the source code.
vsloathe
vim ftw!
Global Moderator
Lifer
*****
Offline Offline

Posts: 1669



View Profile
« Reply #10 on: May 20, 2009, 07:04:14 PM »

I have done a TDD like spider for finding XSS and sql-injection issues in my projects...

I wonder if your spider just checks form inputs, or if it actually checks every vector? Smiley
Logged

hai
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #11 on: May 20, 2009, 08:07:54 PM »

its checked as many as I could think of and figure out at the time. I dont run it anymore as it was ASP.
It was created from and exploit seeking app i acquired.

Im sure it missed stuff, but the 1 app that was heavily attacked was never breached, at least that I am aware of.
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
Pages: [1]
  Print  
 
Jump to:  

Perkiset's Place Home   Best of The Cache   phpMyIDE: MySQL Stored Procedures, Functions & Triggers
Politics @ Perkiset's   Pinkhat's Perspective   
cache
mart
coder
programmers
ajax
php
javascript
Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks


Valid XHTML 1.0! Valid CSS!