Calendar
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
Recent Entries
Come On In, Rails-The Water's Warm
Shan's Simple Examples: File uploads with Flex and ColdFusion
Recent Comments
Google Calendar API - Creating a new Calendar with ColdFusion
Steve Julian said: When and where are you going to post the finished CFC's ? Thanks
[more]
Three Phases of Programmer Development
Pat Branley said: I normally think of those phase 2 people as 'programmers' and the phase 3 people as 'developers'.
I...
[more]
New Job Title: Front End Engineer
Sean Corfield said: Well, there's always the excellent Fusion Authority Quarterly Journal...
[more]
Down To The Wire: HTTP Sniffers
Brian M said: I second the mention of the Charles Web Debugging Proxy that Tariq mentioned. It is fantastic. It s...
[more]
New Job Title: Front End Engineer
Patrick said: Heya Sean. Good point. I never understood how they did things over there at SysCon, and I understand...
[more]
Archives By Subject
Business of Software (4) [RSS]
ColdFusion (318) [RSS]
Conferences (6) [RSS]
Databases (87) [RSS]
Flex & Flash (109) [RSS]
Fusebox (87) [RSS]
General Development (29) [RSS]
Google (9) [RSS]
Hardware (5) [RSS]
JVM & Java (132) [RSS]
Linux (20) [RSS]
Miscellaneous (254) [RSS]
Performance (8) [RSS]
SeeFusion (36) [RSS]
Shan's Simple Examples (7) [RSS]
User Interface (3) [RSS]
Windows (5) [RSS]
Archives By Poster
Daryl Banttari (10)
Nat Papovich (29)
Patrick Quinn (36)
Shannon Hicks (22)
Steve Nelson (21)
Tyson Vanek (3)
Evils of Global Variables when Unit Testing
Let's jump right to some code.
<cfargument name="email">
<cfset var getsomething="">
<cfquery name="getsomething" datasource="mydsn">
select *
from sometable
where email='#arguments.email#'
</cfquery>
<cfreturn getsomething/>
</cffunction>
versus:
<cfset var getsomething="">
<cfquery name="getsomething" datasource="mydsn">
select *
from sometable
where email='#session.user.getEmail()#'
</cfquery>
<cfreturn getsomething/>
</cffunction>
They look pretty similar right? Near identical. Neither is really easier or harder to read. Performance wise, I suspect you couldn't see much of a difference. If you're thinking to yourself, "Aww geez Steve Nelson is about to go on a week long rampage about something." You would be right!!
Here's the problem that I see and it's pretty simple. Unit Testing.
The first one is dead simple to create a unit test for. You cfinvoke the method, pass in an email. Boom! You're done. Hell you could write a bunch of different unit tests in a matter of minutes to try out different types of email addresses. Maybe throw in some Japanese kanji just to see what happens. Maybe do a SQL injection test since I didn't use cfqueryparam in my example. Then setup your testing process to continually test them with a test harneness runner.
The second function is dramatically more difficult to unit test. You can try the same thing, cfinvoke the method (no arguments). Damn. Error. It doesn't know what session.user is. So now you have to create another CFC. (Which you were going to do anyway right? I guess we need to unit test that one too) Create the CFC with at least one method getEmail. Great. Run the first test it works. Beautiful. But now let's try our Japanese kanji test. How do we change that value returned by getEmail? We have two choices. The obvious choice is to edit the original getEmail method and have it return the static Japanese kanji string. Fine. But now you're no longer testing the english string. So the better choice is to create ANOTHER method called updateEmail which modifies the email address returned. Then the second unit test has to call the updateEmail() before it calls getEmail(). Great it works! Now run the first test again... aw damn it! It's still displaying the kanji. What the heck? Oh right, the first one ALSO has to call the updateEmail() method because it's a session scope variable. The Session scope is a persistent global variable. One unit test affected another unit test when global variables are used.
Did I lose you? Good. I was trying. Chew on that a bit. I'll come back to some unit testing code soon. Personally I prefer passing in every argument my method needs.
-Steve Nelson
By the way, if you're looking for CF Architects or simply some extra CF hands, send us an email or give us a call at +1-970-223-2278. We're about to finish up a few projects and will have some free time shortly.


I guess the big question is how do you determine if something is 'difficult' to test? 'Difficult' is so relative it seems like it would be a useless comparison. no?
Simple arguments (strings, numbers etc) are less difficult to test than complex arguments (objects).
Therefore the code smells like flowers instead of garbage. haha
But beyond that, the real point of the Law of Demeter is this:
A method M of an object O may only invoke the methods of the following kinds of objects:
1. O itself
2. M's parameters
3. any objects created/instantiated within M
4. O's direct component objects
You example of referencing the session scope violates these rules, and a result of that violation is that the component is harder to test compared to your version where you pass in the value (now the method is using a parameter, which as you can see above is in line with the rules).
Yuck, that has a bad code smell to it to me. I'm not convinced this law of Demeter really applies to 'scopes' in CF. Does it?
That's right Brian said it. Not Steve! haha :-)
Hey, are you coming to cfunited? Are you speaking?
BEER.
:-)