MXUnit 1.0.8 Released

Friday, November 27, 2009

Los Hombres at MXUnit.org are proud to announce a new smokin' release. Aside from some minor bug fixes, including improvements to the Ant task, and Open Blue Dragon compatibilities (Thanks to Peter Farrell!), we have some sweet features that will make your testing more productive and even downright fun! Ok, that was a stretch ... but check it out anyway... http://mxunit.org/download.cfm

Eclipse Plugin: New data comparison feature. Highlight a failed test and click the little 'book'-looking button in the middle part of the plugin view. It'll pop up a compare dialog and you can use the "next change" and "previous change" buttons on the far right to navigate through the differences.

Note that this will be the last version to support Eclipse 3.3.

Framework: New data driven capabilities via mxunit:dataprovider annotation. Use queries, arrays, and Excel to power your tests.

<cfset name_data = ['joe','taj','mary','juan','hans', 'bjork','chaksa'] /> 

<cffunction name="testNameValidation" mxunit:dataprovider="name_data">
   <cfargument name="name" hint="Each name item in the name_data array" />
   <cfset assertTrue( myObject.validateName(name), "#name# not valid" ) />
</cffunction>


See http://wiki.mxunit.org/display/default/Data+driven+testing+with+MXUnit+dataproviders for details

Note: Application.cfm file is still included and should be removed after install to facilitate integration with frameworks or other applications.

Continuous Integration with Hudson: MXUnit is now being built on a continuous basis. Test results can be viewed here: http://mxunit.org/testresults/index.html and nightly builds can be downloaded from: http://mxunit.org/downloadNightly.cfm

Installation and Default Look and Feel: New logos and layout are incorporated into the default installation.

Also, we'd like to welcome two new MXUnit hombres: Randy Merrill and Bob Silverberg. Randy has been busy doing some much needed project organization and graphics. Bob will be taking on integrating mocking into MXUnit.

Test and Be Happy!
Los Hombres.

This Week in ColdFusion Episode #5

Wednesday, November 25, 2009

The guys put out Episode 5 this week after an an extended break. In this episode, they addressed the question “What processes/practices/tools do you use to help ensure software integrity?”. Brian did most of the talking, and threw around his favorite phrase several times. I can see it now… Brian’s at a cocktail party, the chicks are dancin’, and he’s all “Hey Baby! You got some mad cyclomatic complexity goin’ on!”

OK, OK. All snarkiness aside, this week’s episode touched on three subjects near and dear to me: testing, ANT, and continuous integration. I was thrilled that they spent so much time covering these topics. As they said, each one could fill up a podcast on its own, and I appreciate their honesty here… you can’t just listen to an hour long podcast and be Jonny Test. It takes a long time, and a lot of practice, to get there. Still, the more people out there saying “you need to test, people”, the better. Introductions to the concept, benefits, and resources are never a bad thing, and I think Brian covered these topics as well as can be expected in 60 minutes.

And they gave MXUnit a lot of lovin’ during the show. So, gents, thanks for that! But it’s not gonna get you out of some gentle ribbing. Here goes:

Finger on the Pulse

Your intrepid reporter (uh, me) must confess to some surprise during the first few minutes of the episode. Here are 3 dudes who have been programming in CF for years, who have a frickin’ podcast about CF, but who talked about the CFMeetup almost as if it was some alien thing. Guys… Charlie’s been hosting guest speakers for years on the CFMeetup. The sessions are recorded so you can get them after-the-fact at http://carehart.org/ugtv. This is a tremendously valuable resource for CFers, and I damn near have a hard time believing that people as involved with CF such as yourselves wouldn’t have been on top of that like white on rice.

What’s worrisome to me about this is that if you dudes don’t know about the CFMeetup and carehart.org in general, what’s that mean for the great masses of CF developers who aren’t even as active as you all are, who don’t do a CF podcast? And more importantly, how do we get the word out to more developers about the CFMeetup awesomeness? 

Aside: When I started learning Eclipse plugin development, I struggled with beginner-ish things even after reading a book on the topic. Most newsgroup questions were met with “look at the source”. Fair enough, but… what I really wanted was the answer to “What are the XX most important things a newbie should know about plugin development?”. I wonder how we get the answers to those questions out to new and old CFers alike… it’s not just about code, but also about resources. I wonder how we can all do a better job of connecting developers to the community. We spend so much time worrying about how to evangelize outside the community, but it seems that we need to start thinking about how to connect the people in the community to the excellent available resources that exist that can help make their lives easier. End Aside.

And what about other ways of keeping a finger on the pulse of CF? Having helpful blogs on the radar, knowing helpful people to contact when the going gets rough, etc. I’m in no way suggesting that it’s one’s professional duty to be reading blogs all day, interacting on twitter for hours, attending all the CFMeetups (I rarely do… I catch the ones that interest me at more convenient times, via the recordings) or otherwise engaging in annoying starry-eyed CF fanboi-dom. Simply, I hope that as CF podcasters, you fine fellows can grow into your role as emissaries of our small-but-growing(-at-least-according-to-Adobe) community. When I listen to podcasts for other technologies, I do so because I expect the people behind the mics to be completely in tune with the community. As TWiCF, people are going to expect that of you, and I know you want to deliver.

While I’m heaping un-asked-for responsibilities on you, I think it’s also important that you keep on talking about .NET and the things you are working on outside of CF. Lord knows the CF community is an insular one, and more reasons to lift the head up and look around are welcome.

Get involved. You’ll be better for it, and so will we.

With that ticklish ribbing out of the way, let’s move on.

Unit Testing vs. TDD

Brian spent a lot of time discussing programmatic testing. Good on you, Brian. Clearly he’s a practitioner and knows his stuff. I was also interested in hearing more about the different tools for functional testing. I sure would like to see all these tools in action… the great symphony of testing. How about it, Brian? How about a CFMeetup presentation demo-ing these functional testing tools?

Now, a nit to pick: Brian mentioned once during the episode that there was no difference between writing tests first or last. It’s my experience that there is a tremendous difference between the two. I won’t belabor the point because it’s been done to death (google it), but here’s the bottom line: writing tests first is an act of design. It damn near forces you to write testable code because from the start, you’re thinking, “How can I test this?”. It seems to me that when I write tests first, I end up approaching Uncle Bob’s SOLID principles almost naturally.  However, when I wait till afterwards to test, I miss out on that design opportunity and sometimes find that I have written less-testable code.

I will be the first to admit this is because I am not all that bright, and that other far more capable developers come by easy-to-test code quite naturally, as if the ability were bequeathed unto them by The Almighty Himself.

Furthermore, there is certainly no lack of debate around the desirability of easy-to-test code. More than a few developers believe that writing test first is a crippling exercise, atrophying the brain, because you’re thinking about testability and not the bigger picture of the system. In addition, there are those who believe that thinking about testability inevitably leads to Frankenstein, contorted designs (accessors/mutators where there otherwise wouldn’t be; reliance on non-void functions when if you weren’t testing, the function wouldn’t return void; exposing more methods as public when they should be private, etc). All fair points, and I’ll leave it to bright people to argue over while I go write code.

So: “having tests” (and running them frequently) is helpful for catching regression bugs. Writing tests first is helpful as an act of component design which – to many – leads to higher quality software.

P.S. If you’re interested in other podcasts or videos covering TDD/BDD, Hanselminutes has had a few gems. The interviews with Scott Bellware and Roy Osherove are classics. And you can’t go wrong listening to Joel and Jeff dis TDD and SOLID on the stackoverflow podcast. Finally, in the NSFW category, is Baltimore’s own, the incomparable Brian Liles.

Continuous Integration

I’ve been using the Hudson continuous integration server at work since May and am quite taken with it. I’ve written about it before so won’t belabor the point. But Brian mentioned that he’d like to hear if anyone else out there has any suggestions regarding CI. So… I do. Brian mentioned that having the build server email you on every build becomes a bit much, and I heartily agree. In fact, one of the reasons Hudson impresses me so much is its plugin ecosystem. Specifically, the ‘Extended email plugin’ is outstanding for noise reduction. If you want to read more, have at it.

Other Resources

Brian mentioned ANT several times, so I thought I’d point out Jim Priest’s excellent ANT wiki as a wonderful resource for CFers getting into ANT. In addition, for those interested in learning more about Selenium, Mike Henke has written a decent amount about it. And, finally, check out http://carehart.org/ugtv and search for both ANT and Selenium to find presentations on the topic.

Wait, what? That’s all?

This week’s TWiCF review has turned into less a review of the episode and more just a general meandering about the topics they discussed. Why is that? Well, because I don’t want to be your Cliff’s Notes. Go and download the episode and listen to it. It’s a good one!

Till Next Time

Thanks again, gents, for another enjoyable episode. I’m looking forward to the next one.

Marc, out

Anonymity, Accountability, and Credibility in Blogging

Wednesday, November 18, 2009

One literal definition of anonymity is "without a name". In many contexts I respect people's right to anonymity and privacy if they so choose. However, producing and consuming information is a moral activity [ET], and as such, author identification is critical to the subject's credibility and evolution.
"Publicly attributed authorship indicates to the readers that someone is taking responsibility for the analysis, conversely, the absence of names signals an evasion of responsibility. Readers can follow up and communicate with named sources. Also, names may have reputation for credibility - or not." [ET]

I was motivated to write about this subject when I knowingly engaged in a discussion with an Anonymous commenter on the MXUnit blog. My general rule of thumb is not to engage any Anonymous dialogs, but there was something about this one that caught my attention. Regardless of the reason, I began the discourse, and I am glad I did because it got me thinking, but not so much on the subject of the discussion, which is irrelevant, but rather on the subject of anonymity and credibility. We went back and forth, me and Anonymous. I was looking for proof or citations on some small point and I also wanted to know with whom I was speaking, but I never asked or demanded, which was my failed responsibility. I now conclude that the points the commenter made are 100% invalid. They're invalid not because of their intended or intrinsic merit, they're invalid because Anonymous is not willing to be accountable, and accountability is a precondition for the credibility of information.

This speaks to the broader question of anonymity in the context of the blogging and the web, too. As an information producer or consumer does anonymity do anyone any good at all? Could anonymity possibly do damage? When it comes to discourse, such as expressing ideas on technical issues, today I believe that anonymity doesn't have a place and should be discouraged. So, anonymous comments are now disabled on the MXUnit blog.

I suspect that if you're not willing to take ownership of what you write or say, that maybe you shouldn't say it.  This may be the simple litmus test we should follow.  If we're concerned about backlash maybe the answer is not perpetuating anonymity but creating a stronger culture of acceptance, open mindedness, and freedom.


bill shelton

[ET] Edward Tufte - http://www.edwardtufte.com/tufte/books_be

Data-Driven testing with MXUnit's DataProviders

Wednesday, November 11, 2009

What are DataProviders?

Often in unit testing, you will want to run a test function for multiple inputs. Imagine you have a reformatFullName() that parses a string like “Smith, Bob” into “Bob Smith”. And in your test case, you would like to test your reformatFullName() function for a bunch of different inputs to ensure that you’ve covered common cases and also edge cases.

One common approach to this method is to specify the list/array/whatever – the collection of inputs – in the test function, and then write a loop inside the test function. This is a perfectly reasonable approach, though it does lead to some boilerplate.

DataProviders essentially remove the boilerplate; in other words, DataProviders offer a way for you to specify multiple inputs, but without having to construct the looping. In addition, in MXUnit, you have multiple built-in DataProviders at your disposal, which will be covered in other documentation and blog entries. For now, let’s look at a simple case: an array dataprovider.

How do I use DataProviders in my unit tests?

I Palindrome I

For this example, I wanted to have a little fun, so I chose the classic CS101 problem of Palindromes. I think back to my first programming course – Introduction to Programming in C – and distinctly remember the teacher’s frustrated attempts to drill recursion into our thick skulls. One of the problems he used to demonstrate it was Palindromes, i.e. How do you know if a word is the same forwards and backwards (“mom”, “dad”, etc)?  The teacher used rubber bands; he had us “act out” a palindrome. Oi, poor guy. Anyways…

Before we get into DataProviders, let’s start with a very simple test:

component extends="mxunit.framework.TestCase"{

        function setUp(){
                checker = new PalindromeChecker();              
        }

        function palindromeChecker_Should_ReturnTrue_ForPalindrome(){
                assertTrue(checker.isPalindrome("mom"));
        }

}

That’s a good start, but it doesn’t cover cases where the input isn’t a palindrome, and it sure feels incomplete, doesn’t it? Now, let’s look at a testcase that uses an array DataProvider. In here, we’ll specify an array of palindromes and tell MXUnit: Hey, MXUnit, use this array to run my test, one time for each element in the array:

component extends="mxunit.framework.TestCase"{

        function setUp(){
                checker = new PalindromeChecker();
                //set up dataprovider
                variables.palindromes = ["wow","mom","dad","eye","marccram","bob","poooooooooooop"];              
        }

        /**
        *@mxunit:dataprovider palindromes
        */
        function palindromeChecker_Should_ReturnTrue_ForPalindromes(String theWord){
                //debug(theWord);
                assertTrue( checker.isPalindrome(theWord), "word #theWord# should have been flagged as a palindrome" );
        }

}

Here, we create an array named “palindromes”. Then, in the test, we specify the custom attribute ” and set its value to “palindromes”. MXUnit will see that its been given a dataprovider, see that palindromes is an array, and will run the test one time for each element in the array. One other thing about this test function  should jump out at you: it takes a parameter. Typically, tests return void and accept no params. So why do we need this? Simply, MXUnit will pass the current value in the array into the argument which we’ve specified named “theWord”. If you run this test and uncomment the debug(theWord) statement, then hit ctrl-B on the test case in the MXUnit view in Eclipse, you’ll see each value as the test runs.

sshot-3

And now, let's add a negative test:

component extends="mxunit.framework.TestCase"{

        function setUp(){
                checker = new PalindromeChecker();
                //set up dataproviders
                variables.palindromes = ["wow","mom","dad","eye","marccram","bob","poooooooooooop"];
                variables.notPalindromes = ["woww","momm","marc","eyee","bbobbb","poooeeiop"];
        }
        

        /**
        *@mxunit:dataprovider notpalindromes
        */
        function palindromeChecker_Should_ReturnFalse_ForNonPalindromes(String theWord){
                assertFalse( checker.isPalindrome(theWord), "word #theWord# should not have been flagged as a palindrome" );
        }

}

Now that we’ve got some tests – and they should be failing b/c we haven’t created a PalindromeChecker.cfc yet – let’s implement the functionality. We’ll do the braindead simplest way first (which is probably the way you would want to do it in real life):

/**
*@hint checks an input string for Palindrome-ness.
*
*/
component{      
        //how I'd program it if this were for a production system
        public boolean function isPalindrome_simple(String theWord){
                return theWord == reverse(theWord);
        }

}

And now let’s have some recursion fun:

/**
*@hint checks an input string for Palindrome-ness.
*
*/
component{
        //use recursion to get it; this is simply to demonstrate recursion
        public boolean function isPalindrome(String theWord){
                //the "base" case... the simplest case we can have that will return true
                if(len(theWord) <= 1) return true;

                /*compare the far left char with the far right char, and then pass the stuff in between
                the far left and far right back into isPalindrome
                 for input: marccram, calls will look thusly:
                   m == m && isPalindrome(arccra) is true
                        a == a && isPalindrome(rccr)  is true
                         r == r && isPalindrome(cc)   is true
                          c == c && isPalindrome('')   is true
                           len('') <= 1 return true
                */
                return left(theWord,1) == right(theWord,1) && isPalindrome( mid(theWord,2,len(theWord)-2) );
        }

        //how I'd program it if this were for a production system
        public boolean function isPalindrome_simple(String theWord){
                return theWord eq reverse(theWord);
        }

}

If you run your tests now, you should see them pass. For fun, you could put calls to isPalindrome() and isPalindromeSimple() in each of these tests as a sanity check.

How do I get these DataProviders?

Great question. As of this writing, the DataProvider functionality is in Subversion, and we’re prepping a release. If you just gotta have it right now, but you don’t want to check it out from SVN, let me know and I’ll whip up a nightly build.

Stay tuned for more documentation about the other new DataProviders in MXUnit!

--Marc

Windows 7 CMD Access is Denied

Sunday, November 1, 2009

Access is Denied

Windows 7 installed without a hitch, but I noticed that the bat files I use to turn certain programs on and off no longer worked. Specifically, I have bat files that use “NET START” and “NET STOP” to toggle Windows Services. When I’d run those, I’d get “Access is Denied”. This was particularly annoying b/c I use Launchy to run these bat files to quickly set up and tear down an environment, and this new “security feature” was breakin’ my stride. Here’s how to remind Windows that you are its boss.

Do As I Say, Dammit!

Set Command Prompt to Run As Administrator

  1. From the Start menu, filter on “Command Prompt”
  2. Right click on it, select “Properties”. In the “Shortcut” tab, click the Advanced button.
  3. Check the “Run as Administrator” checkbox
  4. Restart your computer

Here’s a screenshot of what these boxes look like (taken with the new Windows 7 “Snipping Tool”):

commandpromptproperties

It was my experience that you need to restart your computer. When I changed these settings initially, it didn’t change the behavior of my bat files at all. Only after restart did my “Access is Denied” problems go away.

Good luck.

--Marc