<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-1973750947775262558</atom:id><lastBuildDate>Fri, 10 Oct 2008 14:04:41 +0000</lastBuildDate><title>MXUnit Blog</title><description>&lt;a href="http://mxunit.org"&gt;MXUnit&lt;/a&gt; is a unit test framework built by ColdFusion developers for ColdFusion developers. This represents some general rants and the like for project related stuff, unit testing, and CF in general.</description><link>http://mxunit.org/blog/</link><managingEditor>noreply@blogger.com (billy)</managingEditor><generator>Blogger</generator><openSearch:totalResults>56</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-6527273881213302011</guid><pubDate>Fri, 03 Oct 2008 13:56:00 +0000</pubDate><atom:updated>2008-10-03T10:29:53.874-04:00</atom:updated><title>Subversion 1.5 Merge Tracking</title><description>This week, I made it my personal mission to learn as much as I could about branching and merging in subversion. This was prompted by a general need in my department to get a better handle on our large, multi-client, shared codebases.&lt;br /&gt;&lt;br /&gt;Up until last year, we used VSS. If you've ever tried using it for branching, it's not pretty. Doable, yes, but not ideal. I'd go so far as to say that for where I work, it simply wasn't robust enough to be an option.   Over a year ago, I was given the go-ahead to do some new projects in subversion. This created some short-term and ongoing pain, what with some stuff in VSS And some in SVN. Still, it had to be done. Unfortunately, change is slow in large organizations, rightfully so sometimes. So we still haven't ported everything over to SVN yet,  in part because there hasn't been a "killer feature" driving us to do so.&lt;br /&gt;&lt;br /&gt;I believe with Subversion 1.5, that killer feature is here: merge tracking.&lt;br /&gt;&lt;br /&gt;If you've ever tried merging with Subversion prior to 1.5, you know that you need to do it with revision numbers. This isn't too tough in easy cases, but consider:&lt;br /&gt;&lt;br /&gt;You create a branch.  It's  a long-running feature branch, maybe taking 2 weeks to complete. Ideally, you'd keep that branch up to date with the latest and greatest from trunk frequently, meaning you'd be merging from trunk to branch a lot. This becomes problematic because you have to keep track of your merge revision numbers; otherwise, you can get "double merges". If you don't keep a log, and you/others don't use good commit comments, it doesn't take long before you find yourself in this position.  Personally... it's just tough to maintain.&lt;br /&gt;&lt;br /&gt;Subversion 1.5 merge tracking aims to eliminate that problem. Essentially, it keeps track of your merges so you don't have to. This way, you simply say "svn merge [TrunkURL]" and it does the deed. It remembers your previous merges. No more double merges.&lt;br /&gt;&lt;br /&gt;I've been working with it on the command line for a bit, and so far, it's great. But ideally, this functionality would be built into the GUI tools we've all come to know and love. For me, that's subclipse and tortoise.&lt;br /&gt;&lt;br /&gt;However, when I tried to figure out how to get those two apps to merge with the new merge tracking, I got stuck.&lt;br /&gt;&lt;br /&gt;And that's the point of this post: how to use these two GUI tools to do merges from trunk to branch, with merge tracking, with svn 1.5&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tortoise&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Had I read the excellent Tortoise docs before I started, I wouldn't have struggled at all with this. But I'm a "jump right in" kind of guy, clicking buttons and banging on things. So after it wasn't braindead simple, I gave up and RTFM (after complaining a lot... that's how I roll).&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;While in trunk, make your changes. Commit&lt;/li&gt;&lt;li&gt;switch to your branch (using tortoise, subclipse, whatever)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Using tortoise, right click on the project in question, select "Merge"&lt;/li&gt;&lt;li&gt;Select "Merge a range of revisions" radio button&lt;/li&gt;&lt;li&gt;in the "URL to merge from", enter the URL to your trunk&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Leave the revision range blank&lt;/span&gt;. This was the central problem I was having!&lt;/li&gt;&lt;li&gt;Click Next&lt;/li&gt;&lt;li&gt;Do a "Test Merge" to see what it will do. If you're comfy with that, click "Merge"&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;In retrospect, this is actually really obvious, so maybe I was just having a momentary lapse of common sense. Possibly being confronted with the "revision" box kept my brain in revision number mode. Although I do swear that I tried it without any numbers but got nothing in the test merge.... but anyways.... it's working now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Subclipse&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I upgraded to the latest Subclipse, which as of this writing is the 1.4 tree. I did a team -- merge, got the normal merge dialog, and couldn't figure out how to get it to do a simple SVN 1.5 merge. It requires revision numbers to work correctly.&lt;br /&gt;&lt;br /&gt;I was pretty surprised that the new merge tracking wasn't built in to subclipse. So, after complaining (see a pattern?), I joined the subclipse mailing list and posted it as a question. There, I learned that I wasn't missing anything, as I was with tortoise. This functionality is indeed not built into subclipse.&lt;br /&gt;&lt;br /&gt;However, it is available in the &lt;a href="http://www.collab.net/downloads/desktops/installing_cdee.html"&gt;Collabnet Desktop&lt;/a&gt;. (for you fast-and-loose types, here's the update URL for eclipse 3.3: http://downloads.open.collab.net/eclipse/update-site/e3.3)&lt;br /&gt;&lt;br /&gt;This is a free plugin that does not replace subclipse but complements it. So I installed it, and now when I do a team -- merge from within Eclipse,  I am confronted with a new set of screens. These screens walk you through doing a 1.5 style merge... Worked like a charm!&lt;br /&gt;&lt;br /&gt;So far, in my limited play with this, I havent hit any snags.&lt;br /&gt;&lt;br /&gt;Bottom line: subclipse doesn't do 1.5 merging, but the collabnet desktop will add this feature right into your existing subclipse 1.4 installation.  One note: when I installed it in eclipse's update manager, I didn't hit any snags. But as with all things plugin related, your mileage may vary.&lt;br /&gt;&lt;br /&gt;Many, many thanks to the folks at Tortoise and Collabnet for the excellent work!</description><link>http://mxunit.org/blog/2008/10/subversion-15-merge-tracking.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-3399844722082151773</guid><pubDate>Thu, 02 Oct 2008 20:40:00 +0000</pubDate><atom:updated>2008-10-02T19:58:43.421-04:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>test automation</category><category domain='http://www.blogger.com/atom/ns#'>announcements</category><title>Ajax Testing with MXUnit, Webdriver, and Firefox</title><description>&lt;p&gt;"Release early and often", is an Agile mantra. I usually wait until something is more stable, but I'm particularly excited about this effort and hope to get some feedback quickly - even better, get some help!&lt;/p&gt;&lt;p&gt;One of the goals we have at MXUnit is to be able to perform not just unit testing, but other types of testing as well - all inside of MXUnit &lt;em&gt;and&lt;/em&gt; using CFML. One big gap and need I see is the ability to test ColdFusion applications via the the user interface &lt;em&gt;and&lt;/em&gt; to test the UI itself. Testing has some catching up to do with the rapid adoption of jQuery, ExtJs, and other Javascript Ajax frameworks. One effort in particular that caught my attention is Webdriver (&lt;a href="http://code.google.com/p/webdriver/"&gt;http://code.google.com/p/webdriver/&lt;/a&gt;). Simon Stewart's smart ideas behind it are to create a simple interface and to be able to use existing browsers. Webdriver has the ability to invoke Firefox and Internet Explorer &lt;em&gt;natively&lt;/em&gt; as well as leverage HtmlUnit. HtmlUnit's main advantage is that it's fast. However, it does not handle JavaScript in the same way most user's browser do - it can, at best , emulate the browser. So, how can we then accurately automate testing in common browsers?&lt;/p&gt;&lt;p&gt;This effort, &lt;strong&gt;CFWebdriver Experimental (&lt;/strong&gt;for the moment), allows you to write tests that call URLs, find page elements, write data to form fields, click buttons, and verify output. Again, the Webdriver interface is intended to be simple, which is very appealing.&lt;/p&gt;&lt;p&gt;Here's some example code:&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&amp;lt;cfcomponent output="false" extends="mxunit.framework.TestCase"&amp;gt;&lt;br /&gt;&amp;lt;cfscript&amp;gt;&lt;br /&gt;function doGoogleSearch(){&lt;br /&gt;driver = createObject("component","cfwebdriver.WebDriver").newInstance("firefox");&lt;br /&gt;driver.get("&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;a href="http://google.com/"&gt;http://google.com/&lt;/a&gt;");&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;q = driver.findElement("q");&lt;br /&gt;q.sendKeys("mxunit");&lt;br /&gt;q.submit();&lt;br /&gt;link = driver.findElementByLinkText("MXUnit Blog");&lt;br /&gt;link.click();&lt;br /&gt;assertEquals("MXUnit Blog", driver.getTitle());&lt;br /&gt;}&lt;br /&gt;&amp;lt;/cfscript&amp;gt;&lt;br /&gt;&amp;lt;/cfcomponent&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;What this does is to start Firefox, invoke Google's home page, find the input named "q", enter mxunit into the input, submit the form, find the link text &lt;em&gt;MXUnit Blog&lt;/em&gt;, click that link, then verify the expected text in the title tag. It works nicely on Windows and Ubuntu! Here's a screen shot of MXUnit and Webdriver testing Google's Ajax Search API example (&lt;a title="http://www.google.com/uds/samples/apidocs/helloworld.html" href="http://www.google.com/uds/samples/apidocs/helloworld.html"&gt;http://www.google.com/uds/samples/apidocs/helloworld.html&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/virtix/SOUxtFHce_I/AAAAAAAAAC8/brLAaUCg_44/s1600-h/cfwebdriver-firefox-mxunit%5B24%5D.png"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; WIDTH: 469px; BORDER-BOTTOM: 0px; HEIGHT: 368px" height="396" alt="cfwebdriver-firefox-mxunit" src="http://lh5.ggpht.com/virtix/SOUxuK8PIlI/AAAAAAAAADA/4t7J7hcHKwU/cfwebdriver-firefox-mxunit_thumb%5B20%5D.png?imgmax=800" width="576" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;This is included in the experimental download .... repeat ... &lt;em&gt;experimental&lt;/em&gt;. ;-) Visit &lt;a href="http://github.com/virtix/cfwebdriver/tree/master"&gt;http://github.com/virtix/cfwebdriver/tree/master&lt;/a&gt; and click the Download button. I'll get this in the mxunit subversion repository this weekend - having problems accessing it M-F/9-5.&lt;/p&gt;&lt;p&gt;The installation instructions are in the README in the download, but it's basically copying the Webdriver jars into the ColdFusion classpath, and making sure they are loaded first. I've tested this on CF8 multi-instance installations on Windows and Ubuntu, and Railo 3 on Windows. &lt;/p&gt;&lt;p&gt;This is the preferred method of installation as of today:&lt;/p&gt;&lt;p&gt;1. Copy /webdriverlib to WEB-INF/lib/webdriverlib&lt;br /&gt;2. Edit WEB-INF/web.xml adding the path to the webdriver jars above&lt;br /&gt;to the BEGINING of the cf.class.path element:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&amp;lt;context-param id="coldfusion_context_88"&amp;gt;&lt;br /&gt;&amp;lt;param-name&amp;gt;cf.class.path&amp;lt;/param-name&amp;gt;&lt;br /&gt;&amp;lt;param-value&amp;gt;&lt;br /&gt;&lt;br /&gt;./WEB-INF/lib/webdriverlib,./WEB-INF/cfusion/lib/updates,./WEB-INF/cfusion/lib,./WEB-INF/cfusion/gateway/lib,./WEB-&lt;br /&gt;INF/flex/jars,./WEB-INF/cfform/jars&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;3. Restart the cf instance&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;4. Try the example1.cfc test and the googleAjaxTest.cfc&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#990000;"&gt;Notes&lt;/span&gt;&lt;/strong&gt;: The README should have enough info to get you up and running. The Internet Explorer implementation is very buggy when running inside of CF. It works sometimes and other times not. There's 2 CFCs (wrappers). These contains only some of the full functionality of Webdriver but should be enough to give you a good taste. If the CFC wrappers don't do what you need, you can always go down the java route and instantiate the java representations and work with those instead. Or better yet, contribute ;-)&lt;/p&gt;&lt;p&gt;Happy Ajax testing!&lt;/p&gt;&lt;p&gt;-bill&lt;/p&gt;</description><link>http://mxunit.org/blog/2008/10/ajax-testing-with-mxunit-webdriver-and.html</link><author>noreply@blogger.com (billy)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-5352315078210705161</guid><pubDate>Thu, 25 Sep 2008 12:07:00 +0000</pubDate><atom:updated>2008-09-25T08:14:47.046-04:00</atom:updated><title>MXUnit 1.0.3 Now Available</title><description>&lt;span style="font-weight: bold;"&gt;A new release of MXUnit is now available. Get it while it's hot.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1.0.3 comprises a "Bug Fix" and a feature.&lt;br /&gt;&lt;br /&gt;The bug in question was thoroughly described by Bob Silverberg &lt;a href="http://www.silverwareconsulting.com/index.cfm/2008/9/15/Strange-ColdFusion-Error-Object"&gt;here&lt;/a&gt;. In a nutshell, the eclipse plugin was bombing when an error was thrown containing a non-string error "Type". This required a simple fix to RemoteFacade.cfc. Props to Bob for finding the bug and working with me to pinpoint the source of the problem! Bob sent me a self-contained set of files that clearly demonstrated the issue. It took me literally 30 seconds to see what he was talking about. A lot longer to identify the source of the problem, mind you, but because Bob took the time to make it easy to duplicate the problem, this bug was fixed really fast.&lt;br /&gt;&lt;br /&gt;The feature came from a suggestion by Randy Merill to enable DirectoryTestSuite to work with relative paths. Previously, it required an absolute path as the Directory argument. Now, it'll take a relative path and try to resolve it using expandPath(). The full discussion is &lt;a href="http://groups.google.com/group/mxunit/browse_thread/thread/68e80a66f59fd560"&gt;here&lt;/a&gt;.  Props to Randy for the suggestion and for contributing the code to make it happen.&lt;br /&gt;&lt;br /&gt;Happy testing.&lt;br /&gt;&lt;br /&gt;--marc</description><link>http://mxunit.org/blog/2008/09/mxunit-103-now-available.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-5918567097371284193</guid><pubDate>Mon, 08 Sep 2008 12:37:00 +0000</pubDate><atom:updated>2008-09-15T07:15:48.316-04:00</atom:updated><title>Designing for testability: today's real-world example</title><description>I'm at work now, staring at Eclipse and a method of approximately 150 lines. It's a method for performing sort order updates.  Someone else, long gone, wrote it. It's not ugly code by any means... just complex.&lt;br /&gt;&lt;br /&gt;And there's a bug.&lt;br /&gt;&lt;br /&gt;A big part of me wants to work through this bug by testing it in the interface. Change the sort orders in the form, hit Submit, add dumps and aborts, comment out the actual database update in the code, and struggle through till I fix the sucker. But damn, I just know that's gonna be painful and slow.  And if I'm going to spend the time fixing it, I might as well capture my work.&lt;br /&gt;&lt;br /&gt;So a-unit-testin' I will go.&lt;br /&gt;&lt;br /&gt;This is the first time I've seen this code, and since I gotta fix a bug in it, I'm wondering.... how easy will it be to write a unit test for this code.  As with most of our stuff, it's database-heavy. And I don't want to let it perform actual database updates and then test the database after-the-fact to confirm that the updates I wanted to happen actually happen.  That right there is one way to describe hard-to-test code: you have to perform updates, then refetch the data to see if the results you expected are true.&lt;br /&gt;&lt;br /&gt;This code I'm looking at has several loops, many nested. I was hoping not to see a bunch of CFQueries inside the loops.  This would've been a rat's nest, virtually impossible to test well. But instead, there's only a single CFQuery chunk, at the bottom of the method. The original programmer did a really smart thing: He built up a big ol' array of the updates he wanted to perform, and then in the end looped over the array and did the database work.&lt;br /&gt;&lt;br /&gt;This is great for 2 reasons:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;It's a lot easier to test arrays for the data they contain than it is to test the database after the fact&lt;/li&gt;&lt;li&gt;Since there's only one chunk of code that performs a database Update, I can easily "turn the update off", thereby not updating the database at all.&lt;/li&gt;&lt;/ol&gt;#2 probably needs some more explanation, so let me show.&lt;br /&gt;&lt;br /&gt;Here's what the code basically looked like to start. I've omitted all the actual logic since it's not important here. The important part is that there's only a single block for the queries, and that block is at the end of the original method:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;cffunction name="moveSection" returntype="array" hint="resorts stuff" access="public"&amp;gt;&lt;br /&gt;  &amp;lt;cfargument name="blah"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;cfset var sections = ArrayNew(1)&amp;gt;&lt;br /&gt;  &amp;lt;cfset var ii = 1&amp;gt;&lt;br /&gt;  &amp;lt;cfset var jj = 1&amp;gt;&lt;br /&gt;  &amp;lt;cfset var kk = 1&amp;gt;&lt;br /&gt;  &amp;lt;cfset var keyList = ""&amp;gt;&lt;br /&gt;  &amp;lt;cfset var updateTemplateSections = ""&amp;gt; &lt;br /&gt;  &amp;lt;!--- assload of logic to build up an array ---&amp;gt;&lt;br /&gt;  .....&lt;br /&gt;&lt;br /&gt;  &amp;lt;!--- process array and extract sectionIDs in order ---&amp;gt;&lt;br /&gt;  &amp;lt;cfloop from="1" to="#arrayLen(sections)#" index="ii"&amp;gt;&lt;br /&gt;      &amp;lt;cfset keyList = listAppend(keyList,sections[ii].sectionID)&amp;gt;&lt;br /&gt;      &amp;lt;cfloop from="1" to="#arrayLen(sections[ii].children)#" index="jj"&amp;gt;&lt;br /&gt;          &amp;lt;cfset keyList = listAppend(keyList,sections[ii].children[jj].sectionID) /&amp;gt;&lt;br /&gt;      &amp;lt;/cfloop&amp;gt;&lt;br /&gt;  &amp;lt;/cfloop&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;!--- finally, do the update ---&amp;gt; &lt;br /&gt;  &amp;lt;cfloop from="1" to="#listLen(keyList)#" index="kk"&amp;gt;&lt;br /&gt;      &amp;lt;cfquery name="updateTemplateSections" datasource="#getDsn()#"&amp;gt;&lt;br /&gt;          UPDATE    templateSections&lt;br /&gt;          SET        sortOrder = #kk#&lt;br /&gt;          WHERE    templateSectionId = #listGetAt(keyList,kk)#&lt;br /&gt;      &amp;lt;/cfquery&amp;gt;&lt;br /&gt;  &amp;lt;/cfloop&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;cfreturn sections&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/cffunction&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As I said, in my test, I want to do two things: Test the array for its data, and ensure the database update doesn't occur.&lt;br /&gt;&lt;br /&gt;This method, as originally written,&lt;span style="font-weight: bold;"&gt; almost gets me there&lt;/span&gt;. To the original programmer (&lt;a href="http://mrmx.blogspot.com/"&gt;my friend Mike&lt;/a&gt;), nice job! The obvious problem here, with respect to testing, is that the update will still happen.  So what to do?&lt;br /&gt;&lt;br /&gt;Since the original code has a single block for the DB update, it's easy for me to pull out that chunk of code into a separate method, and then inside my test, override that method with one that simply doesn't perform any updates.&lt;br /&gt;&lt;br /&gt;I call this "Extract and Override".&lt;br /&gt;&lt;br /&gt;Here's my new code. It now contains 2 methods. I've simply extracted out that last chunk of DB updates into a separate method, and then I call that in the original function:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;cffunction name="moveSection" returntype="array" hint="resorts stuff" access="public"&amp;gt;&lt;br /&gt;  &amp;lt;cfargument name="blah"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;cfset var sections = ArrayNew(1)&amp;gt;&lt;br /&gt;  &amp;lt;cfset var ii = 1&amp;gt;&lt;br /&gt;  &amp;lt;cfset var jj = 1&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;cfset var keyList = ""&amp;gt;&lt;br /&gt; &lt;br /&gt;  &amp;lt;!--- assload of logic to build up an array ---&amp;gt;&lt;br /&gt;  .....&lt;br /&gt;&lt;br /&gt;  &amp;lt;!--- process array and extract sectionIDs in order ---&amp;gt;&lt;br /&gt;  .....&lt;br /&gt;&lt;br /&gt;  &amp;lt;!--- call my new method, which I've extracted ---&amp;gt;&lt;br /&gt;  &amp;lt;cfset performMoveSectionUpdate(keyList)&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;cfreturn sections&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/cffunction&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;cffunction name="performMoveSectionUpdate" access="private"&amp;gt;&lt;br /&gt;  &amp;lt;cfargument name="keyList"&amp;gt;&lt;br /&gt;  &amp;lt;cfset var kk = 1&amp;gt;&lt;br /&gt;  &amp;lt;cfset var updateTemplateSections = ""&amp;gt;&lt;br /&gt;  &amp;lt;!--- finally, do the update ---&amp;gt; &lt;br /&gt;  &amp;lt;cfloop from="1" to="#listLen(keyList)#" index="kk"&amp;gt;&lt;br /&gt;      &amp;lt;cfquery name="updateTemplateSections" datasource="#getDsn()#"&amp;gt;&lt;br /&gt;          UPDATE    templateSections&lt;br /&gt;          SET        sortOrder = #kk#&lt;br /&gt;          WHERE    templateSectionId = #listGetAt(keyList,kk)#&lt;br /&gt;      &amp;lt;/cfquery&amp;gt;&lt;br /&gt;  &amp;lt;/cfloop&amp;gt;&lt;br /&gt;&amp;lt;/cffunction&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Finally, the unit test. Since I've extracted out the actual code that performs the update, it's trivial to override that with MXUnit in the test. All I do is create a new, private function inside the test itself that does nothing.  Then, I use&lt;a href="http://mxunit.org/doc/index.cfm?doc=injectmethod"&gt; injectMethod&lt;/a&gt; to replace the existing function with my new for-testing-only function:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;cffunction name="moveSectionDownResortsCorrectly"&amp;gt;&lt;br /&gt;      &amp;lt;cfset injectMethod(gw, this, "performMoveSectionUpdate", "performMoveSectionUpdate")&amp;gt;&lt;br /&gt;      &amp;lt;cfset sections = gw.moveSection(arg1,arg2,arg3)&amp;gt;&lt;br /&gt;      &amp;lt;!--- perform assertions as needed ---&amp;gt;&lt;br /&gt;   &lt;br /&gt;  &amp;lt;/cffunction&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;cffunction name="performMoveSectionUpdate" access="private"&amp;gt;&lt;br /&gt;      &amp;lt;cfreturn ""&amp;gt;&lt;br /&gt;  &amp;lt;/cffunction&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bottom line: &lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;in my original object, extract out the behavior that I don't want to occur, during my test, into a separate method&lt;/li&gt;&lt;li&gt;in the test, override that method in my original object with a new, innocuous method&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;I'm now free to test the arrays for their data without fear of corrupting the database since I'm no longer performing any updates in the method I want to test. This leads to a more predictable, less brittle, faster test.&lt;br /&gt;&lt;br /&gt;-- marc</description><link>http://mxunit.org/blog/2008/09/designing-for-testability-todays-real.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-3914247512592715147</guid><pubDate>Mon, 08 Sep 2008 11:10:00 +0000</pubDate><atom:updated>2008-09-08T08:01:22.134-04:00</atom:updated><title>RIA + TDD FTW. WTF?</title><description>Carl Jung coined the term "&lt;a href="http://en.wikipedia.org/wiki/Synchronicity"&gt;synchronicity&lt;/a&gt;" to describe events that at first appear coincidental but which are potentially meaningfully connected.... a "meaningful coincidence".&lt;br /&gt;&lt;br /&gt;I've been thinking about this for some time now: that the advent of Rich Internet Applications (RIAs) could potentially be a tremendous boon for encouraging boring old server-side unit testing. Now, you might be thinking: "the two are completely unrelated". You can't get much more disparate. RIAs are sexy, they're hip, they're sleek and fun and whizbang. Unit testing, on the other hand, has got to be the least sexy coding you can do. It's the toothless, saggy-butt, scraggy-haired 4th cousin of cool technologies, at least to many people.&lt;br /&gt;&lt;br /&gt;Cranking out animated heatmap hoogies in flex is toot sweet. Writing "assertEquals(4,query.recordcount)" ain't.&lt;br /&gt;&lt;br /&gt;Back when I started writing web apps in CF, debugging was pretty simple because you had&lt;span style="font-weight: bold;"&gt; easy access to the information you needed in order to debug&lt;/span&gt;. You load a page. If you have problems, you maybe throw in a cfdump/cfabort. Or you submit a form and want to see that the DB update query code looks OK, so you comment out the redirect in your index.cfm file, and then look at the debug output at the bottom of the page to check that your database updates are as expected. Snip snap done.&lt;br /&gt;&lt;br /&gt;But when you're building richer interfaces, this work is often either done asynchronously using javascript (ajax), in which case you can't rely on your old tricks; or, even more difficult, it's done in a movie client (flex/flash, silverlight) and you're even further removed from the information you need in order to do your debugging.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The further removed you are from development-time access to debug information, the more time you spend debugging development-time problems.&lt;/span&gt;  Let that sink in.&lt;br /&gt;&lt;br /&gt;There is no cfdump/cfabort simplicity when your front end is a flash movie making remote calls to your backend CFCs.&lt;br /&gt;&lt;br /&gt;With richer interfaces, the time you spend debugging your backend code increases exponentially.&lt;br /&gt;&lt;br /&gt;Not so sexy anymore, is it?&lt;br /&gt;&lt;br /&gt;But here's the thing: What if, rather than try to debug your code at runtime in the interface, you instead remove the interface from the equation. You stay in CF for your debugging. You get your CFDumps back. In short, you get closer to your data again... you get closer to the information you need to do your debugging.  &lt;span style="font-weight: bold;"&gt;You're no longer so far removed.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is where our ugly cousin, unit testing, comes in for the win. By testing your backend CF code with more CF code, you stay on the server and you catch your problems earlier. You codify the expectations of the code. You think more about the edge cases. You root out bugs earlier in the process and thereby make writing your RIA joyful again. You can focus your front-end efforts on the pizazz because you're not worrying so much that your queries are working as expected  -- you've already worked out the server-side kinks in your tests.&lt;br /&gt;&lt;br /&gt;The common arguments against unit testing -- that it takes too much time, that you write too much code, etc -- start to fall away as it becomes apparent that the time savings you accrue start to overtake the lost time spent trying to debug server-side code from an RIA.&lt;br /&gt;&lt;br /&gt;This is what I've been thinking about: that RIAs make it harder to debug server-side code. Therefore, they encourage more unit testing of server-side code because &lt;span style="font-weight: bold;"&gt;the value proposition of unit testing is clearer when put in contrast to the drudgery of runtime debugging the backend of an RIA.&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;Which leads to my moment of synchronicity today. I had planned on writing this blog post on how RIA development damn near requires backend TDD. Then, I came to work this morning, and in my feedreader was this: Indy Nagpal gave a &lt;a href="http://nagpals.com/blog/index.cfm/2008/9/8/Testing-for-Success--My-presentation-at-Web-on-the-Piste-2008"&gt;presentation on server-side TDD at a recent RIA conference&lt;/a&gt;. Not at CFUnited or CFObjective or the local CFUG. At an RIA conference. I thought that was pretty cool, and it suggests to me that other (way smarter) people are thinking the same thing: that if you're writing rich internet apps, then server-side unit testing is getting harder to ignore.&lt;br /&gt;&lt;br /&gt;--marc</description><link>http://mxunit.org/blog/2008/09/ria-tdd-ftw-wtf.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-6334287180389356017</guid><pubDate>Thu, 04 Sep 2008 11:07:00 +0000</pubDate><atom:updated>2008-09-04T07:37:33.353-04:00</atom:updated><title>MXUnit Eclipse Plugin Test History Feature</title><description>I'm happy to announce the latest feature to the MXUnit Eclipse plugin: Test History. Every time you run a test (or directory of tests), it adds that test to your history. When you want to revisit a test, you can open up the history menu, find your test, and reload it. Here's a screen shot to demonstrate:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mxunit.org/blog/uploaded_images/PluginTestHistory-747605.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://mxunit.org/blog/uploaded_images/PluginTestHistory-747593.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There are a few differences between the JUnit and MXUnit implementations of this functionality, born out of my own frustration with the JUnit plugin. I decided that if I were going to add test history, then I was going to make it work how I always wished the JUnit plugin would behave.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;No duplicate entries. "com.my.SomeTest" will only ever appear once in the list, and will only reflect the last run. If you run that test 20 times, you won't get 20 entries in the list&lt;/li&gt;&lt;li&gt;When running a directory of tests, you see the full path to the directory in the list&lt;/li&gt;&lt;li&gt;It's easy to distinguish between single TestCase runs and Directory runs. Simply, directory runs start with a slash.&lt;/li&gt;&lt;li&gt;A more reasonable start value for remembered test runs. JUnit defaults to 10 items in the history. Dunno why.  MXUnit defaults to 30. Considering that duplicates never appear, this seems like a reasonable default. In addition, changing the default is simple and obvious.&lt;/li&gt;&lt;/ol&gt;There's one thing to note, and I'm still not sure how I feel about this because I haven't worked with it enough to form an opinion yet: Tests retain their relative position in the test history no matter how many times they are run. Let me explain:&lt;br /&gt;&lt;br /&gt;You run Test1.cfc at 7:12:00 AM. This test gets position 1.&lt;br /&gt;&lt;br /&gt;You run Test2.cfc at 7:12:15 AM. This test gets position 1. Test1 is bumped to position 2 (i.e. it is lower in the list of tests in the menu).&lt;br /&gt;&lt;br /&gt;You run /mytests/ at 7:13:30 AM. This test gets position 1. Test2 is bumped to position 2, and Test1 is bumped to position 3.&lt;br /&gt;&lt;br /&gt;So far, this is how you'd expect it to work. Here's where it changes:&lt;br /&gt;&lt;br /&gt;You then select Test1.cfc from the test history and re-run that test.  Now, since this last run makes it "newer", in a sense, you might expect it to show up at the top of the list. However, I am currently opting to keep that test in its original position. This might seem weird, but I'll ask you to reserve judgment until you've had a chance to work with it a bit.&lt;br /&gt;&lt;br /&gt;As always, feedback is welcome.&lt;br /&gt;&lt;br /&gt;Happy testing!</description><link>http://mxunit.org/blog/2008/09/mxunit-eclipse-plugin-test-history.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-104679620061748921</guid><pubDate>Mon, 25 Aug 2008 11:58:00 +0000</pubDate><atom:updated>2008-08-25T08:17:19.732-04:00</atom:updated><title>Eclipse running out of memory?</title><description>At home, where I do most of my experimental development, I have a fairly substantial machine. It's windows, but don't hold it against me. It performs like a mofo. 64-bit, 4GB memory, Core2. At work, I have 32-bit, 2GB memory, Core2.&lt;br /&gt;&lt;br /&gt;I run Eclipse 3.3 with tons of plugins. I generally run eclipse from the command line with 512M heap, using the jdk1.6 JVM&lt;br /&gt;&lt;br /&gt;So imagine my surprise when I start getting OutOfMemory errors from eclipse at home. I traced it to the JBoss plugin, but couldn't figure out for the life of me why it was causing this behavior. I wasn't actively using any of the functionality in the plugin at the time I'd get the errors. I turned off auto-activation at startup for the jboss and a handful of other plugins, but to no avail.&lt;br /&gt;&lt;br /&gt;And this was getting in the way of me getting stuff done. Eclipse "manage configuration" is a flaky piece of shit, so disabling suspect plugins didn't work. Thus, I did what any red-blooded American would do:  wipe out any folders in the  plugins/features directories that referenced jboss. It was time for a fresh start.&lt;br /&gt;&lt;br /&gt;That fixed the memory problems and let me get back to work.&lt;br /&gt;&lt;br /&gt;But honestly.... could you live with that answer? I couldn't.  So off I went. I asked the interwebs, and after nice traipse through various newsgroups and wikis and bugtrackers, I stumbled on a fix. Ooooooh, what a maddening f*cking fix.&lt;br /&gt;&lt;br /&gt;Here's the bottom line: my memory troubles went away when I added this to my startup file:&lt;br /&gt;&lt;br /&gt;-XX:MaxPermSize=256m&lt;br /&gt;&lt;br /&gt;That's all.&lt;br /&gt;&lt;br /&gt;By the way, here's where I ended up: https://bugs.eclipse.org/bugs/show_bug.cgi?id=92250. If you're interested, that bug explains pretty well why I was hitting the memory issues I had. It doesn't explain why it was JBoss plugin causing it... but right now, I don't care.&lt;br /&gt;&lt;br /&gt;I also installed the memory monitor plugin attached to that bug. It's no better than what you get from jconsole, but marginally more convenient than attaching eclipse to a jmx session and typing "jconsole".&lt;br /&gt;&lt;br /&gt;So, if you're getting OutOfMemory errors while running eclipse, and increasing the heap isn't cutting it (-vmargs -Xmx512M), it's possibly not a heap problem but a permgen problem.&lt;br /&gt;&lt;br /&gt;--marc</description><link>http://mxunit.org/blog/2008/08/eclipse-running-out-of-memory.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-40292352333947322</guid><pubDate>Thu, 21 Aug 2008 11:19:00 +0000</pubDate><atom:updated>2008-08-21T07:29:41.133-04:00</atom:updated><title>MXUnit 1.0.2 Now Available</title><description>MXUnit 1.0.2 is &lt;a href="http://mxunit.org/download.cfm"&gt;now available for download&lt;/a&gt;.  This release adds new functionality for mocking/injecting properties into objects at time of test, which arose from &lt;a href="http://groups.google.com/group/mxunit/browse_thread/thread/cd19590dfb1c205c#"&gt;this discussion&lt;/a&gt;. It's similar to the &lt;a href="http://mxunit.org/doc/index.cfm?doc=injectmethod"&gt;injectMethod&lt;/a&gt; functionality introduced in 1.0.1, but for properties instead of methods. &lt;a href="http://mxunit.org/doc/index.cfm?doc=injectproperty"&gt;Details are here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In addition, a few more bugs have been fixed for Railo and openBD compatibility.&lt;br /&gt;&lt;br /&gt;Finally, I want to point out again the eclipse dictionary and snippets that are available in the download. See the "cfeclipse" directory. In particular, check out the copysnippets.xml ANT file. It makes keeping your set of mxunit cfeclipse snippets much easier. It will not tramp on your existing shortcuts, as it only adds/overrides shortcuts whose snippets are in the mxunit package.&lt;br /&gt;&lt;br /&gt;The eclipse dictionary is not the entire mxunit api.... just the public stuff that you care about (assertions, etc).  There are instructions in each directory for how to "install" the dictionary and snippets.&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;br /&gt;&lt;br /&gt;marc</description><link>http://mxunit.org/blog/2008/08/mxunit-102-now-available.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-696508539219310977</guid><pubDate>Thu, 14 Aug 2008 14:18:00 +0000</pubDate><atom:updated>2008-08-14T10:20:42.299-04:00</atom:updated><title>Securing a RemoteFacade.cfc</title><description>Nathan Mische has a nice article on how to let the mxunit see a RemoteFacade.cfc file sitting behind a basic authentication scheme.  Check it out here &lt;a href="http://www.mischefamily.com/nathan/index.cfm/2008/8/13/Basic-Authentication-With-ColdFusion"&gt;http://www.mischefamily.com/nathan/index.cfm/2008/8/13/Basic-Authentication-With-ColdFusion&lt;/a&gt;</description><link>http://mxunit.org/blog/2008/08/securing-remotefacadecfc.html</link><author>noreply@blogger.com (Mike)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-5934334077526034613</guid><pubDate>Tue, 05 Aug 2008 11:29:00 +0000</pubDate><atom:updated>2008-08-05T07:42:47.159-04:00</atom:updated><title>MXUnit eclipse plugin update. This one's for Barney</title><description>A new version of the MXUnit plugin for Eclipse is now available. I know... you're so excited you can hardly contain yourself! Before you hit the update button, here's what's new:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A new "Show Failures Only" button to filter out the passing tests and show you just the bad stuff. This is a persistent toggle, meaning that once you turn it on, subsequent test suites will continue to filter out passing tests until you toggle off. However, if ALL tests pass, the filter is ignored.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A new feature just for Barney Boisvert (&lt;a href="http://www.barneyb.com/barneyblog/2008/07/18/mx-unit-is-slick/"&gt;read here for the inspiration&lt;/a&gt;). This is a small helper for people who use the project-level facade URL feature. This new feature is also documented in the integrated help within the plugin. Thanks for the suggestion, Barney!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A bug fix. Have you ever seen it where you run a bunch of tests, and maybe the console view is open on the bottom of the workbench, and the scrollbars in the test run view get hidden? If you have suffered through this tragic, disgraceful behavior, you can sleep a little easier now. It is gone.&lt;/li&gt;&lt;/ul&gt;Enjoy.</description><link>http://mxunit.org/blog/2008/08/mxunit-eclipse-plugin-update-this-ones.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-3344861379174704030</guid><pubDate>Thu, 31 Jul 2008 17:16:00 +0000</pubDate><atom:updated>2008-07-31T13:34:45.658-04:00</atom:updated><title>Railo, Testing, and Stogies</title><description>Last night, Gert Franz from Railo visited our &lt;a href="http://baltimore-aug.org/index.cfm?event=meetings.showMeeting&amp;amp;meetingId=5"&gt;Baltimore Adobe User Group&lt;/a&gt;. First, thanks to Gert for spending so much time with us. Next, thanks to Nic Tunney for leading the group, as always. Finally, extra special thanks to Bob Clingan for setting it all up.&lt;br /&gt;&lt;br /&gt;So, real quick: Railo is impressive. It's damn near unbelievable that such a small team of people could create a product so solid and forward thinking. Some of my favorite things:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Virtual file system. Treating an ftp site or an S3 instance as just another resource? BADASS.&lt;/li&gt;&lt;li&gt;Railo's notion of contexts. Each app is an isolated thing. We've been working around that problem with CF for a long time. With railo, it's simply not a problem&lt;/li&gt;&lt;li&gt;cfvideo is really, really cool. Now, I know that a lot of people don't want to see this in CF. And I know it won't be in the open source version of Railo. Still.... watching the kinds of sweet things Gert demoed, I can see its value&lt;/li&gt;&lt;/ul&gt;And there's so much more but I don't want to blabber.&lt;br /&gt;&lt;br /&gt;Two other things: I asked Gert if they expected to keep up the same pace of development when it goes open source. One thing he said was that the first thing they do when they get a bug is write a test. They fix the bug, prove it's fixed with the test, and keep that test around forever. We try like hell to do this with MXUnit, by the way. Anyway, he said that he believes part of the reason they can move forward with features is that they just don't have a whole lot of bugs. I took it to mean that their use of TDD contributes to that quality.  So... mad props, Gert!&lt;br /&gt;&lt;br /&gt;Finally, the coolest thing of all: the &lt;a href="http://www.davidoff.com/davidoff/"&gt;Davidoff&lt;/a&gt; site runs on Railo. For those not in the know, Davidoff are a luxury cigar. In fact, I'm so cheap I've never had one. But still... I thought that was rad.&lt;br /&gt;&lt;br /&gt;Here's what I came away with: up until now, my only experience with Railo has been working to get MXUnit running on it successfully. But now, after last night's presentation, I'm definitely going to see if I can get some of our apps at work running on it. I'm particularly interested in looking at the performance.&lt;br /&gt;&lt;br /&gt;When OBD came out, there was nothing about it that made me consider for even a second approaching the subject where I work. With Railo, though, I see definite potential and consider it worth my time to pursue this investigation.&lt;br /&gt;&lt;br /&gt;And it's not just because I got a free t-shirt.</description><link>http://mxunit.org/blog/2008/07/railo-testing-and-stogies.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-3953906257107785808</guid><pubDate>Wed, 30 Jul 2008 21:17:00 +0000</pubDate><atom:updated>2008-08-01T07:08:35.832-04:00</atom:updated><title>Coldbox and the CFEclipse Frameworks explorer</title><description>I just tried installing CFEclipse 3.2 beta again, and I see that coldbox still isn't supported in the Frameworks explorer. So I'm like, "hey, I remember Mark saying that the frameworks explorer was a framework for exploring frameworks", so I decided to dig into the XML and see if I could get it going. So I'm poking around in the cfeclipse code, just getting familiar with what's going on, and I fire up a debug session, and I add a coldbox project, and I set the coldbox.xml.cfm file as a config file, and I open up the explorer, and there's all these rad icons in there. So I'm like, WTF?&lt;br /&gt;&lt;br /&gt;So I open up the frameworks config directory, and lo and behold, there's coldbox right in there already.&lt;br /&gt;&lt;br /&gt;Now, the file timestamps indicate that this was in there before 1.3.2 was released, so I'm not sure what might have happened that this stuff didn't make it into the build. Nonetheless, that saved me a lot of time because all the work was done. However, this didn't solve the central problem, because if the stuff ain't in the distribution, how do I get it in my current CFEclipse install?&lt;br /&gt;&lt;br /&gt;Here's what you do:&lt;br /&gt;&lt;br /&gt;1) download the attached file and unzip it into your eclipse\plugins\org.cfeclipse.cfml.frameworks_1.0.3  directory&lt;br /&gt;&lt;br /&gt;OR, if you want to get it from source:&lt;br /&gt;&lt;br /&gt;1)  check out the cfeclipse frameworks directory from SVN. If you want to save yourself the headaches, just read this (http://trac.cfeclipse.org/cfeclipse/wiki/CheckingOutCFEclipse) and do the team project set thing. it's a snap.&lt;br /&gt;&lt;br /&gt;2) that will get all the cfeclipse code into your workspace. NOT your current plugins directory... your workspace.&lt;br /&gt;&lt;br /&gt;3) go into your workspace, navigate to the frameworks project, and copy the config and icons directories into another temp location&lt;br /&gt;&lt;br /&gt;4) remove the .svn stuff from there&lt;br /&gt;&lt;br /&gt;5) now, take those directories and copy them into your eclipse\plugins\org.cfeclipse.cfml.frameworks_1.0.3  directory&lt;br /&gt;&lt;br /&gt;6) restart eclipse.&lt;br /&gt;&lt;br /&gt;7) find a coldbox project, find the coldbox.xml.cfm file, right click, set as config file, and bam. Done!&lt;br /&gt;&lt;br /&gt;Now, looking at how frameworks explorer works, I gotta tell you: it is unbelievably cool. Mad props to you, Mark Drew, for this gem.&lt;br /&gt;&lt;br /&gt;esher, out!&lt;a href="http://mxunit.org/blog/org.cfeclipse.cfml.frameworks_1.0.3.zip"&gt;org.cfeclipse.cfml.frameworks_1.0.3.zip&lt;/a&gt;</description><link>http://mxunit.org/blog/2008/07/coldbox-and-cfeclipse-frameworks.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-3902321697447209798</guid><pubDate>Wed, 30 Jul 2008 02:07:00 +0000</pubDate><atom:updated>2008-07-29T22:26:09.239-04:00</atom:updated><title>It's not you, Arturo...</title><description>A little over a year ago, I sprung 5 bucks on an Arturo Fuente. Until then, I'd never spent that much on a stogie.&lt;br /&gt;&lt;br /&gt;It was a life-altering cigar. Literally. I've spent more money on Fuentes since then than I ever would've spent on stogies had I stuck with my 1.20/stick cheapo La Fincas. Not life altering in the same way that marriage or children are, not even close. But still...  Fuentes have been my staple stogie, a friend I return to time and again.&lt;br /&gt;&lt;br /&gt;Since then, I've bought boxes of Monte Cristos, smoked kickass Cohibas, Ashtons, and all manner of brands in between. I won 3 monster Gurkha "shaggy" cigars at an event at Cross Street Tobacco in Federal Hill, stickering at 15/stick, and they were magnificent. To the hunchbacked guys huddled over their rolling tables in the forests of Nicaragua and Honduras, a hearty "Thank you!"&lt;br /&gt;&lt;br /&gt;My wife and kids are out of town this week, at my in-laws. I couldn't go b/c of work, but I miss them terribly. So I decided to while away the time with good beers (Dogfish), programming, and cigars. My wife and daughters come home tomorrow (Thank God!), so I decided to spend the last night of my short-lived quasi-bachelorhood with a new stogie.&lt;br /&gt;&lt;br /&gt;I'm sorry, Arturo. It's not you. I still love you. But damn...&lt;br /&gt;&lt;br /&gt;Onyx Maduro, you ....  *gasp*.... complete me. (super ghey reference, I know)&lt;br /&gt;&lt;br /&gt;Lord, what a stogie.  A 2-hour smoke, burnt down to the very nub, and excellent all the way. Most stogies start to suck after an hour or so. They get hot, tarrish, nasty. But this one, jeeeeesh.&lt;br /&gt;&lt;br /&gt;I'm in awe.&lt;br /&gt;&lt;br /&gt;I married my bride at 4 on a Saturday afternoon. My firstborn, Alexis, was born at 10:15 on a Saturday Night. My dear little Sidney was born in the wee hours on a Thursday. Those nights are reserved in the "Best Saturday and Thursday nights of my life".&lt;br /&gt;&lt;br /&gt;Tonight, thanks to you Onyx, gets the Wednesday slot.</description><link>http://mxunit.org/blog/2008/07/its-not-you-arturo.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-365311975251603037</guid><pubDate>Tue, 29 Jul 2008 21:13:00 +0000</pubDate><atom:updated>2008-07-29T17:15:45.904-04:00</atom:updated><title>MXUnit 1.0.1 is now available!</title><description>&lt;a href="http://mxunit.org/"&gt;MXUnit&lt;/a&gt; 1.0.1 is now available for download. This is a small patch release and includes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;var scope fixes&lt;/li&gt;&lt;li&gt;injectMethod functionality for simple mocking&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That last one deserves some mention. Mock frameworks like Brian Kotek's &lt;a href="http://coldmock.riaforge.org/"&gt;ColdMock&lt;/a&gt; and Mike Steele's &lt;a href="http://cfeasymock.riaforge.org/"&gt;CFEasyMock&lt;/a&gt; are excellent tools for mocking collaborators. However, sometimes you want to spoof/override a function in your object under test for the purposes of testing some other function inside that same object. Say you have a function that hits the DB and you'd rather it not. Or you have a function that returns a query and you need to force it to return specific data rather than rely on the state of the database. If those functions are inside your object under test, a mock framework might not be much help here.&lt;br /&gt;&lt;br /&gt;That's why injectMethod was introduced... to solve the problem of mocking functions inside the object under test. &lt;a href="http://mxunit.org/doc/index.cfm?doc=injectmethod"&gt;A full write-up is available here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;By way of history, this functionality came out of a &lt;a href="http://mxunit.org/blog/2008/04/adventures-in-mocking-part-1.html"&gt;previous post on mocking&lt;/a&gt;. I'll be providing a follow-up to that post, in the days to come, to show how that specific unit test changes as a result of injectMethod.&lt;br /&gt;&lt;br /&gt;Happy testing.</description><link>http://mxunit.org/blog/2008/07/mxunit-101-is-now-available.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-8601781774759532243</guid><pubDate>Tue, 22 Jul 2008 16:47:00 +0000</pubDate><atom:updated>2008-07-22T12:47:19.252-04:00</atom:updated><title>Code and Preso: Database Test Patterns for Unit Testing</title><description>&lt;p&gt;Last week's presentation at &lt;a href="http://coldfusionmeetup.com"&gt;http://coldfusionmeetup.com&lt;/a&gt; was wrought with difficulties, but hopefully &lt;em&gt;some&lt;/em&gt; of the concepts came across the frazzled wire ok and folks found a thing or two useful.&lt;/p&gt;  &lt;p&gt;The code and presentation materials are available here: &lt;a title="http://github.com/virtix/zoo/tree/master" href="http://github.com/virtix/zoo/tree/master"&gt;http://github.com/virtix/zoo/tree/master&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Click the &amp;quot;download&amp;quot; button and&amp;#160; you'll be given an option to download either a zip or tar. I've added Mike Rankin's code illustrating how to use SQL Server 2005 snapshots inside of MXUnit to keep your local database sandbox in a known state for testing. This is a great utility for those on SQL 05!&lt;/p&gt;  &lt;p&gt;best,   &lt;br /&gt;-bill&lt;/p&gt;  </description><link>http://mxunit.org/blog/2008/07/code-and-preso-database-test-patterns.html</link><author>noreply@blogger.com (billy)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-9174358228063617194</guid><pubDate>Fri, 11 Jul 2008 18:40:00 +0000</pubDate><atom:updated>2008-07-11T15:19:27.673-04:00</atom:updated><title>New MXUnit goodies and a few backwards compatibility busters</title><description>There are a few small enhancements in the 1.0 mxunit release i wanted to talk about... and one change that will break some of your tests.&lt;br /&gt;&lt;br /&gt;1) definitely check out the cfeclipse directory in the download. it's got snippets, a dictionary file, and instructions for both. for you ANT fans, there's a copy.xml file in there that should make bringing the snippets and keyCombos into your existing stuff a snap.&lt;br /&gt;&lt;br /&gt;2) we don't encourage the (over)use of makePublic(), but it's nice in a pinch. One thing I never liked about it was that when you used it, the "public" version of your private function had a different name. For example, "doSomething" got turned into "_doSomething".  That has been changed so that the name defaults to be the same as the function you're making public. If you have existing code that uses makePublic(), IT WILL BREAK!.  Simply remove the underscore from the function call and all is well&lt;br /&gt;&lt;br /&gt;3) if you were using any of the assertEmpty.... functions in the "MXUnitAssertionExtensions" component, they now behave exactly the opposite of how they did previously. Now, they do what they claim to do, i.e. assert something is empty. We had it backwards before. Blame it on the beer, scotch, stogies, and kids.&lt;br /&gt;&lt;br /&gt;4) there's a new injectMethod() function in TestCase. For now, ignore it. I have a little more tweaking to do before it works properly for lightweight mocking. We'll be putting out a patch for it within the next few days, after we hear from other issues that people have.&lt;br /&gt;&lt;br /&gt;5) the plugin and framework should now work with open bluedragon. If you have any problems with OBD and mxunit, please let us know.  As for railo, I tried it as soon as it released, there was a bug in railo (because we were doing some dumb stuff that exposed the bug), and railo fixed it but i haven't given it another shot. I'm fairly certain that at this point mxunit will not work with railo... at least, the plugin probably won't.  on a side note, i am extremely impressed with railo's responsiveness! extremely. I posted this "issue" one day and i think it was fixed the next. Like my daddy used to say, I didn't know whether to shit or go blind. Regardless, it's because of their responsiveness that we will indeed be making a hearty effort to get mxunit fully working with railo very shortly. &lt;br /&gt;&lt;br /&gt;6) the ant task has been updated and now respects the "excludes" attribute. for me this was a big deal. thanks bill!&lt;br /&gt;&lt;br /&gt;So, any issues with the new release, please post it to the mxunit group or file a bug report at the googlecode site.&lt;br /&gt;&lt;br /&gt;thanks!</description><link>http://mxunit.org/blog/2008/07/new-mxunit-goodies-and-few-backwards.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-8468272941658450999</guid><pubDate>Fri, 11 Jul 2008 16:41:00 +0000</pubDate><atom:updated>2008-07-14T10:13:05.457-04:00</atom:updated><title>MXUnit 1.0 Now Available!</title><description>&lt;p&gt;A really long time in the making, los hombres at MXUnit.org (&lt;a href="http://mxunit.org"&gt;http://mxunit.org&lt;/a&gt;) are finally distributing the first production release of their open source Unit Test Framework and Eclipse Plugin for ColdFusion Developers. &lt;/p&gt;  &lt;p&gt;The big truth is that we want to get this version out because we are chomping at the bit to make MXUnit much more robust and flexible -&amp;quot;We're figuring on biggering and biggering ...&amp;quot; - Dr. Suess &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Improvements since RC-1&lt;/strong&gt;:     &lt;br /&gt;* More documentation and tutorials     &lt;br /&gt;* Dictionary and snippets for CFEclipse     &lt;br /&gt;* assertXPath(...) for testing generated html, xml, and anonymous web pages     &lt;br /&gt;* assertSame()/assertNoteSame() - Thanks Mark Mandel!     &lt;br /&gt;* HTML runner and remote web runner for test suites     &lt;br /&gt;* Test Blaster - recursive test stub generator     &lt;br /&gt;* Ant task: errorproperty/failure property, and more ...     &lt;br /&gt;* J2EE CFML open source (Railo/OBD) comparability issues addressed - Thanks Adam Haskel!     &lt;br /&gt;* And one, maybe two minor bug fixes ;-) &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Upcoming Features&lt;/strong&gt;:     &lt;br /&gt;* Selenium Integration     &lt;br /&gt;* Annotations for flexibility     &lt;br /&gt;* Improved TestSuite constructs     &lt;br /&gt;* Test report generation (in lieu of JUnit reports)     &lt;br /&gt;* And more ... &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Upcoming Events&lt;/strong&gt;:     &lt;br /&gt;* ColdFusion Meetup - &amp;quot;Database-centric Testing w/MXUnit&amp;quot;, Thursday, July 17, 2008. 12:00 Noon EDT     &lt;br /&gt;* Adobe Max 2008 - &amp;quot;Advanced Patterns for ColdFusion Test Automation&amp;quot;, Wednesday, November 19, 9:30 AM&amp;#160; PST &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:     &lt;br /&gt;* Easy to see your data with cfoutput, cfdump, and debug()     &lt;br /&gt;* Easy to run single test functions     &lt;br /&gt;* Easy &amp;quot;directory runner&amp;quot; for running entire directories of tests     &lt;br /&gt;* Easy to test private functions in your components     &lt;br /&gt;* Ability to switch to message-first style assertions to help ease transition from other frameworks     &lt;br /&gt;* A plethora of output formats from which to choose     &lt;br /&gt;* Ant Integration     &lt;br /&gt;* A team actively improving the framework, making testing easier, and providing abundant documentation &lt;/p&gt;  &lt;p&gt;Download the latest version of the framework here: &lt;a href="http://mxunit.org/download.cfm"&gt;http://mxunit.org/download.cfm&lt;/a&gt; and update your MXUnit Eclipse plugin using the following url: &lt;a href="http://mxunit.org/update"&gt;http://mxunit.org/update&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Special thanks out to Sean Corfield all the folks who really kicked the tires and gave good honest feedback! Keep 'em coming ...&lt;/p&gt;  &lt;p&gt;Thanks!    &lt;br /&gt;The Guys at MXUnit.org&lt;/p&gt;  </description><link>http://mxunit.org/blog/2008/07/mxunit-10-now-available.html</link><author>noreply@blogger.com (billy)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-1483601613554898658</guid><pubDate>Tue, 01 Jul 2008 17:01:00 +0000</pubDate><atom:updated>2008-07-01T14:04:45.389-04:00</atom:updated><title>Using MXUnit to Test SQL Server Database Logic</title><description>&lt;p&gt;I need a way to test database logic &lt;em&gt;and&lt;/em&gt; to persist those tests. In the past, I would open query analyzer type in some batch code, hit F5 and visually inspect the results. If all looked good, I would move it to a stored procedure, view, CF code, or some other object. There are a number of problems with this approach, and the one that bugs me the most is that the work product of this process becomes lost. Though I may have something working in the end, the pieces and what I was thinking at the time are gone, and at my age, that means gone &lt;u&gt;forever&lt;/u&gt;.&lt;/p&gt;  &lt;p&gt;Enter MXUnit ... using an xUnit framework to test a database? Why not? Ideally, it would be nice to have an xUnit database tool that allowed me to test snippets of batch code. I know there's sqlunit and dbunit that may work, but where I'm at, our db's are tied down pretty tight, but given a cf datasource and MXUnit, I can get pretty far. I can also wrap stored procedures up in tests and print out reports of database test suite runs for the dbas (more on this one later).&lt;/p&gt;  &lt;p&gt;Here's a little gem that popped up the other day. Did you know you can define a CURSOR object inside of CFQUERY? I didn't, but here's is part of something I wanted to test:&lt;/p&gt; &lt;br /&gt;&lt;pre style="font-family:courier;background-color:#eaeaea;border:1px ridge black"&gt;  &lt;br /&gt;---- Super Simple SQL Date Stuff ----  &lt;br /&gt;DECLARE @fiveMinutesAgo datetime, @rightnow datetime &lt;br /&gt;SELECT @rightnow = GETDATE() &lt;br /&gt;SELECT @fiveMinutesAgo = DATEADD (n, -5, @rightnow)&lt;br /&gt;PRINT @rightnow &lt;br /&gt;PRINT @fiveMinutesAgo&lt;br /&gt;---- End ----&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This simply prints the time the batch was run and that time less 5 minutes - mine eyes verify the correctness. Not too bad; certainly not automated; but, it has a smell that is becoming increasingly intolerable for me. &lt;/p&gt;  &lt;p&gt;Here's the same thing written as an MXUnit test:&lt;/p&gt; &lt;br /&gt;&lt;pre style="font-family:courier;background-color:#eaeaea;border:1px ridge black"&gt;&lt;br /&gt;&amp;lt;cffunction name="testCallingDbDateFunctions"&amp;gt;&lt;br /&gt;  &amp;lt;cfquery name="q" datasource="logparser"&amp;gt; &lt;br /&gt;    DECLARE @fiveMinutesAgo datetime, @rightnow datetime  &lt;br /&gt;    SELECT @rightnow = GETDATE()  &lt;br /&gt;    SELECT @fiveMinutesAgo = DATEADD (n, -5, @rightnow)  &lt;br /&gt;    &lt;br /&gt;    DECLARE dbTestCursor CURSOR FOR  &lt;br /&gt;    SELECT @rightnow as nowDate, &lt;br /&gt;           @fiveMinutesAgo as fiveMinutesAgo;  &lt;br /&gt;    OPEN dbTestCursor;  &lt;br /&gt;    FETCH NEXT FROM dbTestCursor  &lt;br /&gt;    CLOSE dbTestCursor;  &lt;br /&gt;    DEALLOCATE dbTestCursor  &lt;br /&gt;  &amp;lt;/cfquery&amp;gt;  &lt;br /&gt;&lt;br /&gt;  &amp;lt;cfscript&amp;gt;  &lt;br /&gt;    rightNow = q.nowDate;  &lt;br /&gt;    exepectedDate = dateAdd('n', -5, rightNow);  &lt;br /&gt;    fiveMinutesAgo = createODBCDateTime(q.fiveMinutesAgo);  &lt;br /&gt;    debug(q); &lt;br /&gt;    assertEquals(exepectedDate,fiveMinutesAgo,&lt;br /&gt;                "If broken, could be a date bug in CF or SQL.");  &lt;br /&gt;  &amp;lt;/cfscript&amp;gt;&lt;br /&gt;&amp;lt;/cffunction&amp;gt;&lt;/p&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;p&gt;The debug output looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/virtix/SGpi21x6niI/AAAAAAAAACw/jsv1und6Tig/s1600-h/image%5B2%5D.png"&gt;&lt;img style="border-width: 0px;" alt="image" src="http://lh4.ggpht.com/virtix/SGpi3l038rI/AAAAAAAAAC4/ZUNv8O3cyyk/image_thumb.png?imgmax=800" border="0" height="74" width="244" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This looks like a lot of code to test such a simple piece of logic, and it is. But, the cool things about this for me, were (1) I can create a CURSOR object within CFQUERY and the name of the query becomes a reference to the CURSOR, and (2) I can use MXUnit and ColdFusion to run and persist database logic tests.&lt;/p&gt;  &lt;p&gt;More on database testing soon ...&lt;/p&gt;  &lt;p&gt;-bill&lt;/p&gt;</description><link>http://mxunit.org/blog/2008/07/using-mxunit-to-test-sql-server.html</link><author>noreply@blogger.com (billy)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-8769294158914021195</guid><pubDate>Wed, 25 Jun 2008 12:14:00 +0000</pubDate><atom:updated>2008-06-25T08:21:16.004-04:00</atom:updated><title>On twitter... and feeling slightly dirty about it</title><description>Peep dis: within the past year, we hired this young kid named Mike. I call him Facebook (because he's young, natch) and he calls me Gramps. It's great. Anyway, i bust his balls because he's on this twitter thing, and he "tweets", and i'll be damned if that's not the fairiest sounding word ever verbed. Every time I type it I want to kick my own ass.&lt;br /&gt;&lt;br /&gt;So I'm at cfunited and I'm wondering, "is that little bastard doing any work today while I'm gone?" I sign up for twitter and try to follow him, seeing if he's tweeting away every 5 minutes instead of doing whatever it is he does at work. Well, he wasn't tweeting, so I assume he was on youtube or some other time drain.&lt;br /&gt;&lt;br /&gt;Anyway, here's what I'm wondering, now that I'm on this thing: what's the value? What will it bring my life that I don't already have? In what ways are people using it that helps you out day to day?  I'm not asking as a smartass. I'm asking because I really want to know. &lt;br /&gt;&lt;br /&gt;i'm at twitter.com/marcesher&lt;br /&gt;&lt;br /&gt;I don't know why yet. Maybe after every 10 tweets (dammit!) they'll send me a free dunkin donuts gift card or something.</description><link>http://mxunit.org/blog/2008/06/on-twitter-and-feeling-slightly-dirty.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-2038946810617845700</guid><pubDate>Tue, 24 Jun 2008 17:56:00 +0000</pubDate><atom:updated>2008-06-24T13:57:27.223-04:00</atom:updated><title>CFUnited: Automating the Build &amp; Deploy Process with ANT</title><description>I was presenting on an old ghetto laptop that couldn't run connect (although in all fairness to the P.O.S. machine, connect is a total hog.). Anyway, the most important part other than my charm and grace is the code, right? So the presentation, with all promised code, jar file dependencies, etc is &lt;a href="http://mxunit.org/doc/index.cfm#cfmeetup"&gt;here at the bottom of the page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;My "wingman", the goatee'd fellow asking really good questions, asked me another great one the following day and I thought it bore mentioning here. During the 2nd part of the presentation, I demo'd macrodef and used an example of looping over a query of servers, and for each server, running a bat file that would open up a connection to that server. Then, it'd copy the code. Then, it'd run that same bat file and close the connection to the server.&lt;br /&gt;&lt;br /&gt;Currently, our environment is completely locked out of the prod environment, rightfully so. And so in my example, I was saying that the bat file in question would temporariliy open up a connection to each production server and then close that connection.&lt;br /&gt;&lt;br /&gt;My goatee'd wingman asked, "but that doesn't prevent you from running that bat file any other time, does it?" And he's absolutely right.  Here's a case where I'm hoping that our network admins will work with us, understanding that we have nothing to gain by opening up those connections except during the deploy process. But that remains to be seen. This is definitely a case of "let's compromise".&lt;br /&gt;&lt;br /&gt;So, thanks to all who showed up for the session, and extra special thanks for the brave folks who stuck around for the 2nd half of it!&lt;br /&gt;&lt;br /&gt;For the curious and bored, here's the code in question. The contents of OpenOrClose.bat are irrelevant here... it's the concept we were discussing that matters. The "deployToAllServers" target is the big daddy.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;project name="CFUnited (j): SQL, for, MacroDef, and exec" basedir="." default="getServers"&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;target name="init"&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;property name="app.name" value="Client1App" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;property name="dev.root" location="DEVSERVER" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="test.root" location="TESTSERVER" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="locations.dev.clientroot" location="${dev.root}\${app.name}" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="locations.test.clientroot" location="${test.root}\${app.name}" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;property name="locations.dev.customtags" location="${dev.root}\CustomTags" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="locations.test.customtags" location="${test.root}\CustomTags" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;property name="locations.test.deploy" location="${locations.test.clientroot}\deploy" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="locations.test.deployzip" location="${locations.test.deploy}\${app.name}.zip" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- read all our 'secure' properties from this file; this defines the sql.userid and sql.password properties --&amp;gt;&lt;br /&gt;     &amp;lt;property file="unames.properties" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- create a classpath for ANT to use for finding and running the jdbc driver(s) --&amp;gt;&lt;br /&gt;     &amp;lt;property name="jdbclibdir" location="lib" /&amp;gt;&lt;br /&gt;     &amp;lt;path id="jdbc.classpath"&amp;gt;&lt;br /&gt;         &amp;lt;fileset dir="${jdbclibdir}"&amp;gt;&lt;br /&gt;             &amp;lt;include name="**/*.jar" /&amp;gt;&lt;br /&gt;         &amp;lt;/fileset&amp;gt;&lt;br /&gt;     &amp;lt;/path&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- these properties would be better placed in a .properties file --&amp;gt;&lt;br /&gt;     &amp;lt;!-- this will use the jtds.jar in the classpath --&amp;gt;&lt;br /&gt;     &amp;lt;property name="sqlserver.driver" value="net.sourceforge.jtds.jdbc.Driver" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="sqlserver.url" value="jdbc:jtds:sqlserver://localhost:1436/ANT;instance=NetSDK" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- this will use the mysql-connector jar in the classpath --&amp;gt;&lt;br /&gt;     &amp;lt;property name="mysql.driver" value="com.mysql.jdbc.Driver" /&amp;gt;&lt;br /&gt;     &amp;lt;property name="mysql.url" value="jdbc:mysql://localhost/ANT" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- this is where the sql resultset will be stored --&amp;gt;&lt;br /&gt;     &amp;lt;property name="db.output" value="serverslist.txt" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- http://sourceforge.net/projects/ant-contrib --&amp;gt;&lt;br /&gt;     &amp;lt;taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="jdbc.classpath" /&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;target name="getServers" depends="init" description="Queries a db for a list of servers"&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;sql driver="${mysql.driver}" url="${mysql.url}" userid="${sql.username}" password="${sql.password}" classpathref="jdbc.classpath" print="yes" output="${db.output}" showheaders="false" showtrailers="false"&amp;gt;&lt;br /&gt;     select ServerIP from servers where ActiveFlag=1&lt;br /&gt;     &amp;lt;/sql&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!--&lt;br /&gt;&lt;br /&gt; IMAGINE: You have a database table of servers to which you'll deploy.&lt;br /&gt; You want to query for the "active" servers, and for each server&lt;br /&gt; Copy your code onto it. This would assume an active network connection between&lt;br /&gt; the machine you're on and the servers to which you are deploying&lt;br /&gt; --&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;target name="loopOverServers" depends="init,getServers"&amp;gt;&lt;br /&gt;     &amp;lt;loadfile srcFile="${db.output}" property="serverlist" /&amp;gt;&lt;br /&gt;     &amp;lt;for list="${serverlist}" param="server" delimiter="${line.separator}"&amp;gt;&lt;br /&gt;         &amp;lt;sequential&amp;gt;&lt;br /&gt;&lt;br /&gt;             &amp;lt;echo&amp;gt;Copying to @{server}\Apps\${app.name}&amp;lt;/echo&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;             &amp;lt;copy toDir="@{server}\Apps\${app.name}" preserveLastModified="true" includeEmptyDirs="false"&amp;gt;&lt;br /&gt;                 &amp;lt;fileset dir="${locations.test.clientroot}" /&amp;gt;&lt;br /&gt;             &amp;lt;/copy&amp;gt;&lt;br /&gt;&lt;br /&gt;             &amp;lt;tstamp&amp;gt;&lt;br /&gt;                 &amp;lt;format pattern="MM/dd/yyyy hh:mm aa" offset="-5" unit="year" property="customtagfilter" /&amp;gt;&lt;br /&gt;             &amp;lt;/tstamp&amp;gt;&lt;br /&gt;             &amp;lt;copy toDir="@{server}\CustomTags" preserveLastModified="true" includeEmptyDirs="false"&amp;gt;&lt;br /&gt;                 &amp;lt;fileset dir="${locations.test.customtags}"&amp;gt;&lt;br /&gt;                     &amp;lt;date datetime="${customtagfilter}" when="after" /&amp;gt;&lt;br /&gt;                 &amp;lt;/fileset&amp;gt;&lt;br /&gt;             &amp;lt;/copy&amp;gt;&lt;br /&gt;          &lt;br /&gt;         &amp;lt;/sequential&amp;gt;&lt;br /&gt;     &amp;lt;/for&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!--  NOW IMAGINE:&lt;br /&gt;&lt;br /&gt; You want to do the same as above, but you need to open and close the connection to each server&lt;br /&gt; because your network people run a tight ship, and they don't want connections open&lt;br /&gt; between your dev environment and your other environments except&lt;br /&gt; during the brief time it takes to copy code&lt;br /&gt;&lt;br /&gt; --&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;target name="deployToAllServers" depends="init,getServers"&amp;gt;&lt;br /&gt;     &amp;lt;!-- open the connections using a bat file provided to you by your network admins;&lt;br /&gt;     we'll call the bat file using a self-made task that we create with macrodef --&amp;gt;&lt;br /&gt;     &amp;lt;OpenOrCloseConnections action="open" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- call the loopOverServers target and copy all code --&amp;gt;&lt;br /&gt;     &amp;lt;antcall target="loopOverServers" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- close the connections --&amp;gt;&lt;br /&gt;     &amp;lt;OpenOrCloseConnections action="close" /&amp;gt;&lt;br /&gt; &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- MACRODEF: this little gem lits you define your own tasks! --&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;macrodef name="OpenOrCloseConnections"&amp;gt;&lt;br /&gt;     &amp;lt;attribute name="action" default="close" /&amp;gt;&lt;br /&gt;     &amp;lt;!-- imagine: this OpenOrClose.bat is provided to you by your network people to open&lt;br /&gt;     up the appropriate connections, and then close them, for the life of your script.&lt;br /&gt;     In this way, you can directly copy files across the network during a brief window of&lt;br /&gt;     access and then automatically remove that access once the deployment is over --&amp;gt;&lt;br /&gt;     &amp;lt;sequential&amp;gt;&lt;br /&gt;         &amp;lt;exec executable="cmd"&amp;gt;&lt;br /&gt;             &amp;lt;arg value="/c" /&amp;gt;&lt;br /&gt;             &amp;lt;arg value="OpenOrClose.bat" /&amp;gt;&lt;br /&gt;             &amp;lt;arg value="-@{action}" /&amp;gt;&lt;br /&gt;         &amp;lt;/exec&amp;gt;&lt;br /&gt;     &amp;lt;/sequential&amp;gt;&lt;br /&gt; &amp;lt;/macrodef&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- FINALLY, IMAGINE:&lt;br /&gt;&lt;br /&gt; Imagine a table called "Deployments" and a table called "J_Deployments_Servers". And&lt;br /&gt; every time you deploy, you insert a row into the deployments table, get the ID&lt;br /&gt; of that deployment, and for each server you copy code to, you insert a row&lt;br /&gt; into J_Deployments_Servers with some audit information (IP address of machine&lt;br /&gt; from which the deployment was run, the exact time of the copy, etc).&lt;br /&gt;&lt;br /&gt; How would you do that using sql and macrodef up in your loopOverServers target?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; --&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;</description><link>http://mxunit.org/blog/2008/06/cfunited-automating-build-deploy.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-2881985395233297622</guid><pubDate>Tue, 24 Jun 2008 00:33:00 +0000</pubDate><atom:updated>2008-06-24T08:36:14.081-04:00</atom:updated><title>CFUnited Wrapup #341</title><description>All the young hipsters have been busily writing up their cfunited wrapups, so I'm jumping into the fray mostly because it will force me to review all I learned. I want to get one or two sentences about each session to force concision. There's nothing like writing about something to help you crystallize your thoughts. Ideally I'll get out of the blather I'm about to spew at least a 3-minute sales pitch for why my company should consider sending people next year or why people I work with should consider going even if the company doesn't buck up.&lt;br /&gt;&lt;br /&gt;This whole business of "who should go to conferences?" is a topic i have a lot of thoughts on, but it is a post for another time. Like you care, I know.&lt;br /&gt;&lt;br /&gt;So, here goes:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;keynotes:&lt;/span&gt; I'm not gonna dis michael smith's keynote b/c i want to present at cfunited next year. As for ben/adam's adobe keynote, the "announcements" have been covered ad nauseum by all the other cool kids. I have two additional thoughts: #1) those of you dying for hibernate.... have you ever worked with it? do you know what the implications are? I've built some fairly sizable java apps in spring and hibernate, and I tell you this: it's no magic bullet. More on that for another post maybe. And #2) talk about nail-in-the-coffin for CFEclipse. Up until now the teasing has been mild. Annoying, but mild. Now it's bordering on hand-down-your-pants. I asked adam haskell if he'd consider contributing to cfeclipse. He summed it up thusly: "Did you hear today's keynote?" Nuff said. &lt;span style="font-family:courier new;"&gt;Project Explorer --&gt; org.cfeclipse.cfml --&gt; right click --&gt; close project.&lt;/span&gt; I hope I'm wrong, but I doubt it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #1: Jeremy Kadlec, Advanced Search with SQL Server&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bottom line: It's easy! I had no idea how powerful full text searching was in sql server. Must consider, though, the performance implications of inserts/updates when the text index is set to auto-build, similar to the considerations of loading up tables with indexes. For me, this will come down to load testing. ain't no way to guess through this one... just gotta do it and see what happens. Also, must remember to add mssqltips.com to the ol' feed reader.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #2: Bill Shelton, Patterns for test automation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As Bill said, "that's a pretty grown up title!". So was the session description. Still, it was obvious that much of the audience needed an Intro to Unit Testing presentation first. This is fine, but it slowed bill down b/c he had to answer a lot of questions ("what's an assertion?"). But he did manage to have at least enough time for to get across probably the two nuggets of gold he was going for: #1) dependency injection is critical for getting the most out of unit testing. #2) how to use cfeasymock.  It's is so much clearer to me now having seen him use it. I don't know why, but the docs for cfeasymock just confuse me. Bill's example -- probably because he thoroughly explained exactly the kinds of dependencies he was trying to  get around -- was crystal clear. Maybe it's because i was sitting in the front row, but his example nailed it for me. Bill works on ubuntu so couldn't give the preso over connect, but I do hope he can find the time to do the recording soon.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #3: Hal Helms, Object Oriented best practices&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hal seemed sick. But his message -- question the pseudo-OO that some folk preach -- came across nicely.  I love Hal's "question everything" approach. He makes you a better programmer just by reinforcing the idea that it's OK not to believe everything you read, that you gotta think for yourself and earn your answers. Practical example: "bean" objects that are just bags of getters and setters, with no behavior and just data, aren't very useful for us CFers and are more pain, less gain. This is in line with Hal's general "don't start with the data(base)" philosophy. Anemic domain = bad. Objects that do stuff = good. I'm going to give hal's 6-line-maximum method approach a shot and see how it changes the way I think about code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #4:&lt;/span&gt; Nic Tunney was supposed to talk on section 508 and RIA, and I was going to go to that. But he didn't show, so I called it a day.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #5: Adam Haskell, Code Reviews and Mentoring BOF&lt;/span&gt; (birds of  a feather)&lt;br /&gt;&lt;br /&gt;You know what: I have too many thoughts on this one. I want to let it gestate and write about it down the road. Interestingly (to me and only me), this BOF was probably the session whose content is nearest to my heart. So I want to say more at a later time. MAD props to Adam for leading this extremely important and eye-opening session.&lt;br /&gt;&lt;br /&gt;But tell me: why can't conference organizers have the event staff put the rooms into a circle or square for the BOFs? c'mon, people. pay the extra 100 bucks and get the rooms properly configured.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Thursday, Session #1: Clark Valberg and Hal Helms, Prototyping for Smarties.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's an example of how chance encounters change the course of things. On Wednesday, I was standing in the lunch line with no one to talk to, and behind me was this girl and two dudes. Girl is on the phone. She hands it to dude #1. Within 10 seconds I'm thinking to myself "this is possibly the funniest conversation I've ever heard". Girl was Anne Nelson (Hi Anne!). Dude was Clark Valberg, who called himself the sometimes "office minstrel". Damn is he funny. Anyway, next morning I'm reviewing the schedule and I saw he was talking with Hal, and although I hadn't originally planned to attend this session, I figured that i just had to see it. Something about meeting him in the lunch line.  Anyhoo....&lt;br /&gt;&lt;br /&gt;This session was useful for me but would've been about 10 times more useful for the project management department where I work. I'm going to try really hard to get a few PMs to watch the connect preso with me. It was excellent.  Hal's story about Joe the Warehouse guy really drove home the notion of the near-impossibility of nailing down specs, and coding to them, when the specs are driven by a select few and not the people using the software. Classic case of "this is what we thought we needed but it's not what we needed". We fight this where I work all the time and so it's a topic that's becoming really hot. This one hit home.&lt;br /&gt;&lt;br /&gt;Now, I know that the one person out there reading this is gonna be like "duh, go agile". To which I reply, try turning around a battleship just because it's going to hit the little tiny fishies in its way. Change is slow in big companies. Change is slower when leaders aren't strong. Change is excrutiatingly, unbearably slow when leaders simply cannot lead. Read into that what you will.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #2: Mark Drew, Fresh Air with Aptana&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've seen 3 or 4 presentations on AIR. Maybe b/c of seeing them, or maybe b/c mark drew was so great,  this one was the best of the lot. Not the concept of AIR, but the "how to get started cranking out apps". I think seeing him go from scratch, through creating a fairly realistic app, is what made this one so good. For me, there's nothing like a "start at the start" kind of presentation to make an abstract thing more concrete. As a speaker, here's what you want: you want the audience to think "yeah, I could go home and get started with this right away", and that's what I felt after this session. When you present, you're not just competing for the hour during which your session is held, but for the limited free time that your attendees can commit to new things when they get back to work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Host My Site Keynote:&lt;/span&gt; I sat in the lounge room shooting the breeze with some of my new favorite people, Adam Haskell and the kroger crew (9-v Lauren, Tony, Bob, Steve, Dustin, and Chad). Hostmysite could've given away free beer and I'd still have had a better time doing exactly what i was doing.&lt;br /&gt;&lt;br /&gt;Without doubt the best thing about conferences, if you're not afraid of people, is meeting new people. I spent a lot of time with the wonderful gal and guys from kroger over the 3 days and am very thankful for that. If I have a regret it's that I didn't get to throw down those massive hotel beers with em. Maybe next time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #3: End to end performance tuning.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Honestly, it felt really rushed. I actually don't remember much useful stuff from the first part, but maybe that's because I was tired. I'm going to download the slides and review it again, though. One cool thing was hearing Nate Nelson talk about the stuff I'm absolutely clueless about, i.e. hardware.&lt;br /&gt;&lt;br /&gt;My 2-sentence summary: use trusted cache, index your databases, and the type of raid you choose will be a trade-off between redundancy and performance (unless you like blowing wads on raid-10). Exactly one week ago when hearing "raid 10" I would've responded like a drooling idiot. Thanks for showing me the light Nate.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #4: Patrick Quinn, Server Down and how to react.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I had to leave about 15 minutes early to prepare for my presentation, so I missed the good stuff at the end. I really liked his notion of "crash patterns" though. This is one I'll be reviewing down the road as I try to ramp up with more load testing. One thing I'm still waiting for though is some smarty to finally tell me "here's how to find what's holding your memory". I haven't had this satisfactorily answered yet. Probably because it's not so cut and dry. But please, someone smart, can you please tell me how to figure this out? In 5 minutes? Otherwise, I'm going to have to get all Java Profiler on your ass, and you don't want that. When I open up YourKit and point it at CF, puppies die and angels lose their wings. For the good of the little children, please, answer this question.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #5: Me, Automating stuff with ANT&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I had a wonderful time. But damn I wanted to see Adam Howitt's presentation on amazon ec2, which was going on at the same time. Oh well... the things you suffer for your craft.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Friday, Session #1: Dan Wilson, Refactoring procedural to OO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OK, I'm biased here. Within 10 minutes of meeting Dan Wilson at the speaker dinner on Tuesday, he offered me a beer (note to teratech: please, buck up for some drinks next time). The rest was history and if I lived in bumf**k north carolina, where dan lives, i think we'd be fast friends. that's a joke dan will get because I live in bumf**K pennsylvania, aka "pennsyltucky", so the degree of bumf**kness is debatable and kind of funny, in a "more people have been arrested for having sex with sheep in my state than yours, buddy" kind of way.&lt;br /&gt;&lt;br /&gt;Also, Dan was incredibly gracious by engaging my wife in conversation while i geeked out with mike brunt at the crime museum talking clustering beside the corpse. If it weren't for dan, I don't know who'd have been more bored, the dead guy or my wife.&lt;br /&gt;&lt;br /&gt;Anyway, dan's a very articulate speaker and had great examples. The contrast of the original kalendar app, in all its nasty spaghetti glory, with the newer OO version, was stark and told the story better than an hour lecture could have. I think I may ask dan for permission to use this presentation as the basis for some teaching/learning where I work. Or i might just steal it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #2: Michael Collins, deploying into large scale environments.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This one, I think, was just not what I was looking for. I was hoping for more practical examples of how to move all your code from a central place into 1000 servers during a production deployment. I didn't get that. That's not Michael's fault, just a difference in expectations. If you don't know what car files are, this was a good talk. One thing he did support, though, was keeping code on a SAN, which we're fighting for at work. So having someone from adobe say "yes, this is a good thing" will go far for me. He did talk about creating sort of a "reference" ear file that you could deploy. Now, I might just be a complete mouth-drooling douchebag, but if i have a farm of dozens/hundreds/thousands of servers, is moving a 200MB ear file across the network to all those servers realistic? i didn't think so either. maybe that's why he pushed shared/network code so much.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #3, Luis Majano, Intro to Coldbox&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Mine eyes have seen the glory, and it is coldbox!&lt;br /&gt;&lt;br /&gt;Holy freakin' crap.  Tell you this, if you're going to do event-driven programming, you gotsta have an execution monitor. This framework feels like it was built by 10 people who want nothing more than to help you do your job kickass, day in, day out.  I spoke with 5 or 6 different people right after the presentation, and the reaction was eerily the same: "this is the first framework that actually excites me and makes me want to use it". This will sound teh ghey, but during the presentation I was thinking of &lt;a href="http://www.oopsla.org/oopsla2007/podcasts/invited-talks/keynote0102-kathy-sierra.mp3"&gt;kathy sierra's mantra&lt;/a&gt; of "helping your users kick ass". Coldbox isn't "look how smart Luis is" (very). It's "look how good you can be".&lt;br /&gt;&lt;br /&gt;Very soon I'm going to have a (rare) opportunity to do a greenfield app at work, and I'll be putting coldbox to the test with it. This is the same feeling I had about Spring about 2 years ago, and I've not regretted that decision one bit.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #4: Mike Brunt, High-availability CF Clustering&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bottom line, load test. I really liked mike's no-nonsense demo of watching a cluster work under load. He brought servers down, put them back online, and we saw the results. Also, mad props to kurt wiersma who, as an audience member, gave the 30-second explanation of how to do URL recording in JMeter (my load test app of choice). I never knew that!!!  thanks Kurt. Although that app mike was using was pretty darn sweet.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Session #5: Elliot Sprehn, Internals of CF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Um, uh. I'm no community fanboy, eagerly reading blogs all hours of the night, keeping my finger on every pulse and generally being "with it". But I read my fair share. Where the hell did this dude come from? A few weeks ago I see his name on Ben Nadel's blog, he's talking good smack, and I'm like "I gotta see this dude's talk at cfunited". So i switched to it on my schedule, and holy bejesus is this dude good. Outstanding talk. Note to the youngins in the crowd: you gotta work reeeeeeeeaaaaaaallll hard to get as good as elliot.&lt;br /&gt;&lt;br /&gt;I will not do his talk a disservice by attempting to sum up any of it. It's best seen from the source. But i will say that his point about "hey, people, this undocumented stuff ain't gonna change" is one I'm more than willing to listen to. But seriously, if you only have one hour to live, and you're not doing anything else, go watch this connect presentation. Fascinating.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Saturday, Session #1: Sean Corfield, Event Driven programming&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was the only session I could catch on Saturday. I think some people might have seen it as an advertisement for edmund. I didn't. I thought he did a fine job of describing event-driven programming in the context of a real framework that supports it. I'm going to try to give more thought later to why exactly this presentation made sense to me, because by rights it should've confused the hell out of me, but it didn't. I think probably it's having spent so much time programming eclipse. Although I honestly believe if I get one thing out of this presentation it's a fresh perspective on eclipse plugin programming. Go figure.&lt;br /&gt;&lt;br /&gt;I'm still dubious about debugging event-driven apps, though, without a proper mechanism for doing precisely that, especially asynch events. This is why the coldbox execution monitor is so appealing, by the way. I've done "debugging through logging", and it's about as enjoyable as a pick-axe to the sphincter.&lt;br /&gt;&lt;br /&gt;Here's high praise, not that it means much coming from me but what the hell: on the way home after the talk, my wife asked me the wifey-est of wife questions: "are you ok? what's wrong?" nothing! I was just in real deep thought, driving slow up 295 thinking of sean's talk.&lt;br /&gt;&lt;br /&gt;Sunday, 6:30 - 8:30 PM: Monster 8-inch Gurkha shaggy cigar and glass of balvenie 12-year to celebrate the excellent week I had.&lt;br /&gt;&lt;br /&gt;This week: back to the daily grind, but reinvigorated and full of ideas.&lt;br /&gt;&lt;br /&gt;Thanks to all the presenters and great people I met. Truly a pleasure!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;My Regrets&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Not meeting chris scott. I've read enough by and about chris scott to know he's the real deal. He seems like a "wild brain", a higher mind, and I wish I had the chance to talk to him and see how his mind works. I hope I get to do that some time.&lt;/li&gt;&lt;li&gt;Not having a better laptop for my presentation. See, I usually borrow a machine from work b/c they're badass, but they were all in use this week. So I had to use my wife's work laptop, which barely runs eclipse. Connect kills it dead, so I couldn't record my presentation while it was happening, and I can tell you it's far better live than when I deliver it without an audience.&lt;/li&gt;&lt;li&gt;Not taking pictures. What was I thinking?  I wish I had a picture flexing with Ben Nadel. O'course, his arms are bigger than my head, but still, it'd have been cool.&lt;/li&gt;&lt;li&gt;Spending 10 bucks for a bottle of delirium tremens.  Stoudts abbey triple, while not as refined and "complex" and sophisticated, is definitely just as enjoyable to my uncivilized pallate and at 36/case is far less expensive&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Next Steps&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download all the slides from the presentations I went to and review them again in a week.&lt;/li&gt;&lt;li&gt;Reinstall that plugin-virus Aptana and start using the code samples.&lt;/li&gt;&lt;li&gt;Set up a load test for our flagship app. Nothing fancy, something simple. Just get started.&lt;/li&gt;&lt;li&gt;We bought seefusion a long time ago... get it set up on our production servers and not just development.&lt;/li&gt;&lt;li&gt;Have a talk with my bosses about getting more people involved next year.&lt;/li&gt;&lt;li&gt;Talk with my mentee at work about him presenting next year.&lt;/li&gt;&lt;li&gt;Pour a 40 on the curb for my dead homey cfeclipse&lt;/li&gt;&lt;li&gt;Find one large method in one component and break it down into methods of 6-lines. Decide: what'd I gain?&lt;/li&gt;&lt;li&gt;Find one component that's not tested because of dependency difficulty and put cfeasymock to work on it. Decide: what'd I gain?&lt;/li&gt;&lt;li&gt;Schedule a meeting with PM to watch Clark and Hal's presentation.&lt;/li&gt;&lt;li&gt;Check out mssqltips.com&lt;/li&gt;&lt;li&gt;Start thinking of a topic to present next year. I'm thinking "Java Profiling your CF Server".&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Again, thanks to everyone I met, everyone who presented, and the fine folks at teratech for putting on the show!&lt;br /&gt;&lt;br /&gt;Marc</description><link>http://mxunit.org/blog/2008/06/cfunited-wrapup-341.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-4994456252820849494</guid><pubDate>Fri, 13 Jun 2008 17:49:00 +0000</pubDate><atom:updated>2008-06-13T14:02:47.745-04:00</atom:updated><title>My CFUnited Schedule</title><description>This is the first time I've been to cfunited since 2002, when it was CFUN. I really wanted to go this year, and since I wasn't in time to get it on my company's budget for this year, I figured the only way I was going was if I were a speaker. So I'm giving an ANT presentation Thursday at 4. I'll be covering all the basics of packaging apps and deploying them, but also getting into neat stuff like using antlib for looping, scriptdef for string parsing, sql, etc. I'm really excited about presenting this topic, primarily because I see how much time ANT has saved us over the past year or so.  I hope to channel the spirits of my cf ant heroes (Luis Majano, Mike Henke, Jim Priest) and give a kickass presentation. Plus, since it's the last presentation of the day, I'm free to stick around and talk more ant after the session (at the bar, with beers. beers and stogies, even better).&lt;br /&gt;&lt;br /&gt;OK, so enough advertisements. Here's what I'm going to this year. I'm going to try to stick around Saturday and attend some sessions, too, but I didn't sign up for any since I'm not sure yet.&lt;br /&gt;&lt;br /&gt;&lt;div id="schedules" class="printable"&gt;                       &lt;div class="schedule-block" id="day-Wednesday"&gt;      &lt;h3&gt;       &lt;span&gt;Wednesday, June 18, 2008&lt;/span&gt;      &lt;/h3&gt;      &lt;div id="day-Wednesday-schedule"&gt;       &lt;table class="data-table schedule" cellspacing="0"&gt;        &lt;tbody&gt;&lt;tr&gt;         &lt;th class="start-time"&gt;Start&lt;/th&gt;         &lt;th class="end-time"&gt;End&lt;/th&gt;         &lt;th class="speaker"&gt;Speaker&lt;/th&gt;         &lt;th class="title"&gt;Session&lt;/th&gt;         &lt;th class="track"&gt;Track&lt;/th&gt;        &lt;/tr&gt;        &lt;tr&gt;&lt;td class="start-time"&gt;8:30AM&lt;/td&gt; &lt;td class="end-time"&gt;9:00AM&lt;/td&gt; &lt;td class="speaker"&gt;Michael Smith&lt;/td&gt; &lt;td class="title"&gt;TeraTech Keynote&lt;/td&gt; &lt;td class="track track-KEY"&gt;KEY&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;9:00AM&lt;/td&gt; &lt;td class="end-time"&gt;10:30AM&lt;/td&gt; &lt;td class="speaker"&gt;Ben Forta&lt;/td&gt; &lt;td class="title"&gt;Adobe Keynote Presentation&lt;/td&gt; &lt;td class="track track-KEY"&gt;KEY&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;11:00AM&lt;/td&gt; &lt;td class="end-time"&gt;12:00PM&lt;/td&gt; &lt;td class="speaker"&gt;Jeremy Kadlec&lt;/td&gt; &lt;td class="title"&gt;Building Advanced Search Capabilities for your web site with SQL Server&lt;/td&gt; &lt;td class="track track-DDT"&gt;DDT&lt;/td&gt;&lt;/tr&gt; &lt;tr class="special-session"&gt;&lt;td class="start-time"&gt;12:00PM&lt;/td&gt; &lt;td class="end-time"&gt;1:30PM&lt;/td&gt; &lt;td class="speaker"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="title"&gt;Lunch&lt;/td&gt; &lt;td class="track track-"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;1:30PM&lt;/td&gt; &lt;td class="end-time"&gt;2:30PM&lt;/td&gt; &lt;td class="speaker"&gt;Bill Shelton&lt;/td&gt; &lt;td class="title"&gt;Patterns for ColdFusion Test Automation&lt;/td&gt; &lt;td class="track track-DDT"&gt;DDT&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;2:45PM&lt;/td&gt; &lt;td class="end-time"&gt;3:45PM&lt;/td&gt; &lt;td class="speaker"&gt;Hal Helms&lt;/td&gt; &lt;td class="title"&gt;Object Oriented Best Practices&lt;/td&gt; &lt;td class="track track-ADV"&gt;ADV&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;4:00PM&lt;/td&gt; &lt;td class="end-time"&gt;5:00PM&lt;/td&gt; &lt;td class="speaker"&gt;Phill Nacelli&lt;/td&gt; &lt;td class="title"&gt;Leveraging Basic Object Oriented Concepts in ColdFusion&lt;/td&gt; &lt;td class="track track-GCF"&gt;GCF&lt;/td&gt;&lt;/tr&gt; &lt;tr class="special-session"&gt;&lt;td class="start-time"&gt;6:30PM&lt;/td&gt; &lt;td class="end-time"&gt;8:30PM&lt;/td&gt; &lt;td class="speaker"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="title"&gt;Networking Event&lt;/td&gt; &lt;td class="track track-"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;8:30PM&lt;/td&gt; &lt;td class="end-time"&gt;9:30PM&lt;/td&gt; &lt;td class="speaker"&gt;Mark Drew&lt;/td&gt; &lt;td class="title"&gt;Improving Quality through Code Reviews and Mentoring&lt;/td&gt; &lt;td class="track track-BOF"&gt;BOF&lt;/td&gt;&lt;/tr&gt;        &lt;/tbody&gt;&lt;/table&gt;      &lt;/div&gt;     &lt;/div&gt;            &lt;div class="schedule-block" id="day-Thursday"&gt;      &lt;h3&gt;       &lt;span&gt;Thursday, June 19, 2008&lt;/span&gt;      &lt;/h3&gt;      &lt;div id="day-Thursday-schedule"&gt;       &lt;table class="data-table schedule" cellspacing="0"&gt;        &lt;tbody&gt;&lt;tr&gt;         &lt;th class="start-time"&gt;Start&lt;/th&gt;         &lt;th class="end-time"&gt;End&lt;/th&gt;         &lt;th class="speaker"&gt;Speaker&lt;/th&gt;         &lt;th class="title"&gt;Session&lt;/th&gt;         &lt;th class="track"&gt;Track&lt;/th&gt;        &lt;/tr&gt;        &lt;tr&gt;&lt;td class="start-time"&gt;8:15AM&lt;/td&gt; &lt;td class="end-time"&gt;9:15AM&lt;/td&gt; &lt;td class="speaker"&gt;Kurt Wiersma&lt;/td&gt; &lt;td class="title"&gt;Leveraging Popular ColdFusion Frameworks To Make Better Applications&lt;/td&gt; &lt;td class="track track-FWC"&gt;FWC&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;9:30AM&lt;/td&gt; &lt;td class="end-time"&gt;10:30AM&lt;/td&gt; &lt;td class="speaker"&gt;Mark Drew&lt;/td&gt; &lt;td class="title"&gt;Fresh AIR: Getting to grips with Aptana and AIR apps&lt;/td&gt; &lt;td class="track track-RIA"&gt;RIA&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;10:45AM&lt;/td&gt; &lt;td class="end-time"&gt;12:00PM&lt;/td&gt; &lt;td class="speaker"&gt;Lou Honick&lt;/td&gt; &lt;td class="title"&gt;HostMySite Keynote Presentation&lt;/td&gt; &lt;td class="track track-KEY"&gt;KEY&lt;/td&gt;&lt;/tr&gt; &lt;tr class="special-session"&gt;&lt;td class="start-time"&gt;12:00PM&lt;/td&gt; &lt;td class="end-time"&gt;1:30PM&lt;/td&gt; &lt;td class="speaker"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="title"&gt;Lunch&lt;/td&gt; &lt;td class="track track-"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;1:30PM&lt;/td&gt; &lt;td class="end-time"&gt;2:30PM&lt;/td&gt; &lt;td class="speaker"&gt;Matthew Woodward&lt;/td&gt; &lt;td class="title"&gt;Real World Flex and ColdFusion&lt;/td&gt; &lt;td class="track track-RIA"&gt;RIA&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;2:45PM&lt;/td&gt; &lt;td class="end-time"&gt;3:45PM&lt;/td&gt; &lt;td class="speaker"&gt;Patrick Quinn&lt;/td&gt; &lt;td class="title"&gt;Server Down - How To Prevent It, And How To React To It&lt;/td&gt; &lt;td class="track track-DDT"&gt;DDT&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;4:00PM&lt;/td&gt; &lt;td class="end-time"&gt;5:00PM&lt;/td&gt; &lt;td class="speaker"&gt;Marc Esher&lt;/td&gt; &lt;td class="title"&gt;Automating the build/deployment process with ANT&lt;/td&gt; &lt;td class="track track-DDT"&gt;DDT&lt;/td&gt;&lt;/tr&gt; &lt;tr class="special-session"&gt;&lt;td class="start-time"&gt;7:00PM&lt;/td&gt; &lt;td class="end-time"&gt;9:30PM&lt;/td&gt; &lt;td class="speaker"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="title"&gt;ColdFusion Celebration&lt;/td&gt; &lt;td class="track track-"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;        &lt;/tbody&gt;&lt;/table&gt;      &lt;/div&gt;     &lt;/div&gt;            &lt;div class="schedule-block" id="day-Friday"&gt;      &lt;h3&gt;       &lt;span&gt;Friday, June 20, 2008&lt;/span&gt;      &lt;/h3&gt;      &lt;div id="day-Friday-schedule"&gt;       &lt;table class="data-table schedule" cellspacing="0"&gt;        &lt;tbody&gt;&lt;tr&gt;         &lt;th class="start-time"&gt;Start&lt;/th&gt;         &lt;th class="end-time"&gt;End&lt;/th&gt;         &lt;th class="speaker"&gt;Speaker&lt;/th&gt;         &lt;th class="title"&gt;Session&lt;/th&gt;         &lt;th class="track"&gt;Track&lt;/th&gt;        &lt;/tr&gt;        &lt;tr&gt;&lt;td class="start-time"&gt;8:30AM&lt;/td&gt; &lt;td class="end-time"&gt;9:30AM&lt;/td&gt; &lt;td class="speaker"&gt;Dan Wilson&lt;/td&gt; &lt;td class="title"&gt;Refactoring to Object Oriented Programming in ColdFusion&lt;/td&gt; &lt;td class="track track-ADV"&gt;ADV&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;9:45AM&lt;/td&gt; &lt;td class="end-time"&gt;10:45AM&lt;/td&gt; &lt;td class="speaker"&gt;Mike Nimer&lt;/td&gt; &lt;td class="title"&gt;Flex 3 For ColdFusion Developers&lt;/td&gt; &lt;td class="track track-RIA"&gt;RIA&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;11:00AM&lt;/td&gt; &lt;td class="end-time"&gt;12:00PM&lt;/td&gt; &lt;td class="speaker"&gt;Multiple Speakers&lt;/td&gt; &lt;td class="title"&gt;Demo Durby&lt;/td&gt; &lt;td class="track track-KEY"&gt;KEY&lt;/td&gt;&lt;/tr&gt; &lt;tr class="special-session"&gt;&lt;td class="start-time"&gt;12:00PM&lt;/td&gt; &lt;td class="end-time"&gt;1:30PM&lt;/td&gt; &lt;td class="speaker"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="title"&gt;Lunch&lt;/td&gt; &lt;td class="track track-"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;1:30PM&lt;/td&gt; &lt;td class="end-time"&gt;2:30PM&lt;/td&gt; &lt;td class="speaker"&gt;Luis Majano&lt;/td&gt; &lt;td class="title"&gt;ColdBox Framework 101&lt;/td&gt; &lt;td class="track track-FWC"&gt;FWC&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;2:45PM&lt;/td&gt; &lt;td class="end-time"&gt;3:45PM&lt;/td&gt; &lt;td class="speaker"&gt;Mike Brunt&lt;/td&gt; &lt;td class="title"&gt;High Availability - Clustering ColdFusion&lt;/td&gt; &lt;td class="track track-DDT"&gt;DDT&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;4:00PM&lt;/td&gt; &lt;td class="end-time"&gt;5:00PM&lt;/td&gt; &lt;td class="speaker"&gt;Elliott Sprehn&lt;/td&gt; &lt;td class="title"&gt;Internals of the Adobe ColdFusion Server&lt;/td&gt; &lt;td class="track track-ADV"&gt;ADV&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="start-time"&gt;4:00PM&lt;/td&gt; &lt;td class="end-time"&gt;6:00PM&lt;/td&gt; &lt;td class="speaker"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="title"&gt;&lt;br /&gt;&lt;/td&gt; &lt;td class="track track-"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;        &lt;/tbody&gt;&lt;/table&gt;      &lt;/div&gt;     &lt;/div&gt;&lt;/div&gt;&lt;br /&gt;See you there!</description><link>http://mxunit.org/blog/2008/06/my-cfunited-schedule.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-7006587461441697254</guid><pubDate>Wed, 04 Jun 2008 14:32:00 +0000</pubDate><atom:updated>2008-06-05T05:00:24.061-04:00</atom:updated><title>GIT with it</title><description>&lt;span style="font-size:100%;"&gt;Unlike Linus Torvalds, I won't call you stupid and ugly if you use CVS or Subversion. If you use VSS, you already know you are stupid and ugly - from 9-5/M-F &lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;font-size:100%;" &gt;I&lt;/span&gt;&lt;span style="font-size:100%;"&gt; am &lt;/span&gt;&lt;span style="font-style: italic; font-weight: bold;font-size:100%;" &gt;very&lt;/span&gt;&lt;span style="font-size:100%;"&gt; stupid and ugly for just this reason. And, the thought of being able to have a distributed network of trust and knowledge  such that we can pull intellectual assets (source code and binaries) directly&lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt; &lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;font-size:100%;" &gt;from each other&lt;/span&gt;&lt;span style="font-size:100%;"&gt; as opposed to a single repository is a fascinating concept and challenges me to think differently. It becomes more of a graph model for collaboration, or a web, rather than some more linear constraint where we are dealing with a single definitive reference for software resources.  This is not so say the there doesn't need be some kind of centralization at times, but when a team is geographically dispersed, sometimes on-line, sometimes off, being able to build software and collaborate efficiently just makes sense.&lt;br /&gt;&lt;br /&gt;Git claims and delivers performance. It is fast. It's merging capabilities are supposed to be strong; and that's next on my list, as that, for me, can be the most painful part of source code management. The security built into git is also very good, from what this inexperienced hack can tell.&lt;br /&gt;&lt;br /&gt;I'm brand new to git but have set up a source tree for MXUnit at &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt;. I hope to keep it in sych with the existing main Subversion repository.  Note that MXUnit has no plans yet to move to git, we're checking it out.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Git – Fast Version Control System&lt;/span&gt;&lt;br /&gt;&lt;a style="font-weight: bold;" href="http://git.or.cz/"&gt;&lt;span style="font-weight: normal;"&gt;http://git.or.cz/&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Git on MySys (Windows fork)&lt;/span&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/msysgit/"&gt;http://code.google.com/p/msysgit/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Google Tech Talk: Linus Torvalds on git&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=4XpnKHJAok8"&gt;http://www.youtube.com/watch?v=4XpnKHJAok8&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;MXUnit pulic Git repository&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;a href="http://github.com/virtix/mxunit/tree/master"&gt;http://github.com/virtix/mxunit/tree/master&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'd be interested to hear about your experience with git ...&lt;br /&gt;&lt;br /&gt;thanks,&lt;br /&gt;bill&lt;/span&gt;</description><link>http://mxunit.org/blog/2008/06/git-with-it.html</link><author>noreply@blogger.com (billy)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-8612840693181141715</guid><pubDate>Tue, 03 Jun 2008 11:42:00 +0000</pubDate><atom:updated>2008-06-03T08:25:19.100-04:00</atom:updated><title>How I set up CFEasyMock</title><description>&lt;a href="http://cfeasymock.riaforge.org/"&gt;CFEasyMock&lt;/a&gt; is the latest mock framework for CF. It's based on the popular &lt;a href="http://www.easymock.org/"&gt;EasyMock framework for Java&lt;/a&gt; and is quite a nice port from what I can tell. If you set it up exactly as the author has packaged it, and if you already have cfcunit installed, then you should have no problems getting started.&lt;br /&gt;&lt;br /&gt;If you're like me and aren't keen on the way it's distributed, and if you want to change CFEasymock's own unit tests to use MXUnit, here's what to do&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Changing directory structure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I don't like how it has 4 separate directories for a single framework. It's built like so:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;easymock&lt;/li&gt;&lt;li&gt;reflect&lt;/li&gt;&lt;li&gt;samples&lt;/li&gt;&lt;li&gt;test&lt;/li&gt;&lt;/ul&gt;Why are samples and test outside of easymock? I don't know.&lt;br /&gt;Why is reflect outside of easymock? because it's technically a separate project. OK, fair enough. I'll live with that (for now).  So here's what I did:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt; Download latest cfeasymock&lt;/li&gt;&lt;li&gt; copied reflect into my webroot&lt;/li&gt;&lt;li&gt; copied easymock into my webroot&lt;/li&gt;&lt;li&gt; copied test and sample into that easymock directory&lt;/li&gt;&lt;li&gt; copied easymock word doc into easymock directory&lt;/li&gt;&lt;li&gt; copied reflect word doc into reflect directory&lt;/li&gt;&lt;li&gt;created a new eclipse project for the easymock directory&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;Setting it up to use MXUnit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In Eclipse, selected the "sample" and "test" directory&lt;/li&gt;&lt;li&gt;Hit CTRL-H to pop up the search box&lt;/li&gt;&lt;li&gt;enter org.cfcunit.framework.TestCase into the "Containing Text" box. &lt;/li&gt;&lt;li&gt;Filter on *.cfc&lt;/li&gt;&lt;li&gt;Select "Selected Resources" radio button if it's not already selected&lt;/li&gt;&lt;li&gt;Click Replace button&lt;/li&gt;&lt;li&gt;Enter mxunit.framework.TestCase into the "With" box. &lt;/li&gt;&lt;li&gt;Click "Replace All"&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Running the tests in MXUnit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As of now, all but two of the tests should go OK. The two that won't are in ResultTest.cfc because they use an assertion from CFCUnit that MXUnit doesn't copy verbatim, the "AssertClass" assertion. MXUnit has an AssertIsTypeOf(), though, so we'll just swap the two.&lt;br /&gt;&lt;br /&gt;In testCreateReturnResult, change the cfset assertClass.... to this:&lt;br /&gt;&lt;br /&gt;&amp;lt;cfset assertIsTypeOf(returnResult, "easymock.Result", "value returned from createThrowResult() is not of type easymock.Result" ) /&amp;gt;&lt;br /&gt;&lt;br /&gt;In testCreateThrowResult, change the cfset assertClass to this:&lt;br /&gt;&lt;br /&gt;&amp;lt;cfset assertIsTypeOf(throwResult, "easymock.Result", "value returned from createThrowResult() is not of type easymock.Result" ) /&amp;gt;&lt;br /&gt;&lt;br /&gt;Now, all tests should pass when you run them in MXUnit.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Running the "Samples"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the Samples directory there are two test cases: TestClassUnderTest and TestUser. If you run them in the directory structure we've just created, they'll fail with a "Could not find the ColdFusion Component or Interface "sample.User".... and so on.  So we just need to prefix the "sample" with "easymock." to get the right component path.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In Eclipse, highlight the "sample" directory&lt;/li&gt;&lt;li&gt;Hit CTRL-H, do a replace-all of "sample." with "easymock.sample."&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;That'll get "TestUser" to run OK.&lt;br /&gt;&lt;br /&gt;From there, I tried running the TestClassUnderTest tests, but I got errors about "Could not convert the value of type class coldfusion.runtime.TemplateProxy to a boolean. And for now, I don't have the time to debug it. If I get some time I'll post back here.&lt;br /&gt;&lt;br /&gt;With that bit of cleanup out of the way, I'm ready to start easymocking. I look forward to having this tool in the toolbelt. As I get time, I hope to add more posts on using easymock in the real world.&lt;br /&gt;&lt;br /&gt;--marc</description><link>http://mxunit.org/blog/2008/06/how-i-set-up-cfeasymock.html</link><author>noreply@blogger.com (Marc Esher)</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-1973750947775262558.post-3681637815378594264</guid><pubDate>Sun, 18 May 2008 19:56:00 +0000</pubDate><atom:updated>2008-05-18T16:36:55.176-04:00</atom:updated><title>Heading to Webmaniacs, and Bleeding for my Art</title><description>I know, the title is a tad histrionic. But hear me out: the &lt;a href="http://www.rougehotel.com/index.html"&gt;hotel rouge&lt;/a&gt; looks really, really cool. But then I looked at the parking rates: 20 bucks for day parking, and 30 bucks for overnight.   WTF?!&lt;br /&gt;&lt;br /&gt;Still, even though the parking will bleed me, I'm super excited about the sessions, and about presenting our workshop on mxunit.&lt;br /&gt;&lt;br /&gt;I plan on getting into DC about 8:00 tonight (Sunday), then heading down to the hotel bar for a beer.  DC is a great beer town so I hope the bar lives up to the city's reputation.&lt;br /&gt;&lt;br /&gt;So, if you're in the hotel bar tonight and see a short bald/blonde dude looking really surly about paying out the yingyang for parking.... Come drink a beer with me!</description><link>http://mxunit.org/blog/2008/05/heading-to-webmaniacs-and-bleeding-for.html</link><author>noreply@blogger.com (Marc Esher)</author></item></channel></rss>