<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9072572603236462376</id><updated>2012-01-31T04:37:51.099-08:00</updated><category term='Tomcat'/><category term='Behavior Driven Design (BDD)'/><category term='Continuous Integration'/><category term='agile'/><category term='groovy'/><category term='integration testing'/><category term='Hudson'/><category term='FIT testing'/><category term='team'/><category term='Ubuntu'/><category term='EasySpec'/><category term='Inversion of Control'/><category term='testing'/><category term='altnetconf'/><category term='Guice'/><category term='Test Driven Design (TDD)'/><title type='text'>Test Infected</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>45</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-2146068571286052317</id><published>2009-04-09T22:31:00.000-07:00</published><updated>2009-04-09T22:40:22.645-07:00</updated><title type='text'>Installing SQL Server 2008 with Visual Studio 2008 SP1</title><content type='html'>When I brought up my most recent Windows development machine (on Vista Ultimate), I installed Visual Studio 2008 Professional with SP1 embedded.  Later, I went to install SQL Server 2008 including the "Management Tools" option so that I could have SQL Profiler and the other tools.  That's when the problems started.  The installation was blocked failing this rule:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Rule "Previous releases of Microsoft Visual Studio 2008" failed&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Imagine my surprise when I found &lt;a href="http://support.microsoft.com/kb/956139"&gt;this article&lt;/a&gt; indicating that the problem was that I didn't have VS 2008 SP1 installed.  I'm sure that I was running SP1, because I was seeing SP1 bugs manifested (requiring hotfixes).  These bugs were only present in SP1 as of the time of this writing.  It seems that a required registry key or something didn't get set when I installed Visual Studio.  I really didn't want to get into hacking on the registry.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;I downloaded the Visual Studio 2008 SP1 installer and ran it.  This took quite a while, and I'm now up much later than I planned.  However, I can report that this got me past the installation block.  I'm not sure if I'll have to reinstall those hotfixes or not...&lt;br /&gt;&lt;br /&gt;Happy coding!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-2146068571286052317?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/2146068571286052317/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=2146068571286052317' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2146068571286052317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2146068571286052317'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/04/installing-sql-server-2008-with-visual.html' title='Installing SQL Server 2008 with Visual Studio 2008 SP1'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-6400741196598075319</id><published>2009-03-11T08:17:00.000-07:00</published><updated>2009-03-11T08:39:25.096-07:00</updated><title type='text'>Standing on the Side of Right</title><content type='html'>Anyone that has worked with me will tell you that I am passionate about getting things right.  I like to fix things that are broken.  I like to improve my skills.  I like to challenge others around me to improve and I expect them to do the same for me.  I rarely miss the opportunity to improve myself or to encourage others to prove.  I love teachable moments.&lt;br /&gt;&lt;br /&gt;This morning, after reading &lt;a href="http://netcave.org/ACultureOfPotentialAssholesSexualHarassmentInIT.aspx"&gt;Alan's thoughtful post on sexual harassment&lt;/a&gt; in the IT industry, I wonder where I have missed those teachable moments in the non-technical areas of my career.  Though I don't have any women on my current team, I have worked with them in the past at other jobs.  Though I have never done anything as egregious as what Alan describes, I hope that I have treated them with respect and dignity.  I believe that I have.  However, I am sure that I have also missed opportunities to help men around me be respectful, considerate, and just plain decent.&lt;br /&gt;&lt;br /&gt;Though the original article was about sexual harassment, this is an issue that transcends gender.  Sexual harassment is merely a single form of being a jerk.  At my company, like many others, there are rules against being a jerk about certain taboo areas: gender, religion, age...  We shouldn't be relying on corporate policy to define decency.&lt;br /&gt;&lt;br /&gt;True confession time.  I'm an ass.  I hope that today I am less of an ass than I was ten years ago.  But, truth be told, I still have some ass-like tendencies that pop up when I least expect them.  I hate that.&lt;br /&gt;&lt;br /&gt;Some of you know me well enough to know my beliefs.  I am happy to say that I am a follower of Jesus Christ and that I have trust in Him alone to guide me through this life and the next.  If my beliefs are to be consistent with my actions, then I must continue to fail forward in this area of how I treat those around me.  To be consistent, I must treat everyone with respect and encourage others to do the same.  To be consistent, I must be willing to admit when I am wrong (often).  To be consistent, I must build other up rather than tearing them down.  To be consistent, I must treat people like... people.&lt;br /&gt;&lt;br /&gt;That brings me back to the original topic of this post.  We must treat our female peers with the respect that they deserve, and we must insist that others do as well.  Look around you.  Are you standing up for others?  Are you defending the sanctity of the lives around you?  Where, dear reader, do you need to improve?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-6400741196598075319?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/6400741196598075319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=6400741196598075319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6400741196598075319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6400741196598075319'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/03/standing-on-side-of-right.html' title='Standing on the Side of Right'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-6809915969269508331</id><published>2009-01-31T13:47:00.000-08:00</published><updated>2009-01-31T14:25:09.186-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Guice'/><category scheme='http://www.blogger.com/atom/ns#' term='Inversion of Control'/><title type='text'>When Collections Are Configuration - binding Collections in Guice</title><content type='html'>Classes that create their own internal domain objects and simple objects are typically not a problem for testability.  The problem comes when classes are creating their own dependent &lt;span style="font-style:italic;"&gt;services&lt;/span&gt; internally.  Then, you've got a problem cutting the testing seams.  Creating these dependent services is what Dependency Injection is best at.  Using your IoC container to create &lt;span style="font-style:italic;"&gt;everything&lt;/span&gt; constitutes container abuse.&lt;br /&gt;&lt;br /&gt;However, I will use my IoC container of preference to create populated collections if the contents of those collections are inherently configuration.  For instance, assume we have the following class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Validator&amp;lt;T&amp;gt; {&lt;br /&gt;  private Collection&amp;lt;Validation&amp;lt;T&amp;gt;&amp;gt; validations;&lt;br /&gt;  private ValidationProblemReporter reporter;&lt;br /&gt;&lt;br /&gt;  public Validator(Collection&amp;lt;Validation&amp;lt;T&amp;gt;&amp;gt; validations, &lt;br /&gt;    ValidationProblemReporter reporter) {&lt;br /&gt;    this.validations = validations;&lt;br /&gt;    this.reporter = reporter;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public validate(Collection&amp;lt;T&amp;gt; elements) {&lt;br /&gt;    for(Validation&amp;lt;T&amp;gt; validation : validations) {&lt;br /&gt;      for(T elements : elements) {&lt;br /&gt;        if (!validation.isValid(element)) {&lt;br /&gt;          String m = element.toString() + " fails " + validation.toString();&lt;br /&gt;          reporter.reportProblem(m);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;we frequently use a validation pattern that calls for a Collection&amp;lt;Validation&amp;lt;T&amp;gt;&amp;gt;.  These validations vary from project to project, but the Validator&amp;lt;T&amp;gt; class is the same from project to project.  The actual validations used varies depending on the validation requirements of the project and the type of the object that is being validated.  Each instance of Validation&amp;lt;T&amp;gt; is pure business logic, and each is properly unit tested.&lt;br /&gt;&lt;br /&gt;Determining what to put in the Collection&amp;lt;Validation&amp;lt;T&amp;gt;&amp;gt; is simply a configuration concern.  This is where it is easy to use the IoC container.  Since Guice is what I typically use, that's what I'll show.&lt;br /&gt;&lt;br /&gt;Example:  Say, we are dealing with Customer objects that we are importing into the system.  These customers are being imported from someone else's system into ours.  So, we are not sure if each customer object is valid and we only want to import the objects that are valid.  There are multiple ways to bind up the collection of validations, among them are using TypeLiteral and using a marker class.  For this, I will show the marker class, but I've also used TypeLiteral.&lt;br /&gt;&lt;br /&gt;So, since I want to validate Customer, I create a class like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class CustomerValidations extends ArrayList&amp;lt;Validation&amp;lt;Customer&amp;gt;&amp;gt; {&lt;br /&gt; //marker class&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, I'll write a marker for the validator:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class CustomerValidator extends Validator&amp;lt;Customer&amp;gt; {&lt;br /&gt;  @Inject&lt;br /&gt;  public CustomerValidator(CustomerValidations validations, &lt;br /&gt;    ValidationProblemReporter reporter) {&lt;br /&gt;    super(validations, reporter);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To get Guice to inject the dependencies into the CustomerValidator, we'll need to bind CustomerValidations and ValidationProblemReporter.  So, I would have a Guice Module that looks something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public MyModule extends AbstractModule {&lt;br /&gt;  public void configure() {&lt;br /&gt;    bind(ValidationProblemReporter.class).to(ConsoleReporter.class);&lt;br /&gt;    bind(CustomerValidations.clas).to(CustomerValidationsProvider.class);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We'll have to write the provider for the CustomerValidations:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class CustomerValidationsProvider implements Provider&amp;lt;CustomerValidations&amp;gt; {&lt;br /&gt;  public CustomerValidations get() {&lt;br /&gt;    validations = new CustomerValidations();&lt;br /&gt;    validations.add(new CustomerShouldHaveAName());&lt;br /&gt;    validations.add(new CustomerShouldHaveAnEmailAddress());&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    return validations;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This cuts a very nice seam to configure which validations we want to run over our customers.  I can easily write a unit test that asserts what validations we have configured.  In fact, if order is important, then I can check that as well.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class CustomerValidationsTest {&lt;br /&gt;  @Test&lt;br /&gt;  public void we_should_do_the_right_things_in_the_right_order() {&lt;br /&gt;    CustomerValidationsProvider provider = new CustomerValidationsProvider();&lt;br /&gt;    CustomerValidations validations = provider.get();&lt;br /&gt;    Iterator&amp;lt;Validation&amp;lt;Customer&amp;gt;&amp;gt; iterator = validations.iterator();&lt;br /&gt;&lt;br /&gt;    assertEquals(CustomerShouldHaveAName.class, iterator.next().getClass());&lt;br /&gt;    assertEquals(CustomerShouldHaveAnEmailAddress.class, iterator.next().getClass());&lt;br /&gt;    assertFalse("Should not have any more", iterator.hasNext());&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, we have locked down our configuration such that if we change the validations, we have to change this test.  I wouldn't always lock the configuration like this, but I often do.&lt;br /&gt;&lt;br /&gt;Guice allows you to unit test your configuration (since it's all Java).  Figuring out what needs tested and what doesn't can be an art form.  You'll get a better feel for it with experience.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-6809915969269508331?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/6809915969269508331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=6809915969269508331' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6809915969269508331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6809915969269508331'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/01/when-collections-are-configuration.html' title='When Collections Are Configuration - binding Collections in Guice'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-6056833472315251200</id><published>2009-01-22T21:19:00.000-08:00</published><updated>2009-01-23T13:31:51.777-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><title type='text'>Hudson Default Ant</title><content type='html'>Most Hudson configuration is self-explanatory and easy to find in the web configuration.  Many props go to the developers of Hudson because it is quite easy to setup and use.  However, there are a couple of things that I've found lately that don't seem to be documented in the Hudson docs.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Configuring Ant&lt;/h3&gt;&lt;br /&gt;From the Hudson dashboard, click on&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;Manage Hudson -&gt; Configure System&lt;/code&gt;&lt;br /&gt;or you can simply navigate to&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;http://your-server-here/hudson/configure&lt;/server&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Look for the section labeled "Ant" and add your Ant installations by clicking "Add" and providing a name and the absolute path for ANT_HOME.  This couldn't be simpler.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Default Ant&lt;/h3&gt;&lt;br /&gt;When you are configuring a build, you can tell Hudson which Ant you want to use.  You may either use one of the named Ant installations that you previously added, or Hudson gives you the option of using the "Default Ant."&lt;br /&gt;&lt;br /&gt;For some reason, I was thinking that I had somehow set the only Ant installation that I added as the default (since it was indeed the only one).  But, this was not the case, and my build failed with this console output:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;FATAL: command execution failed.Maybe you need to configure the job to choose one of your Ant installations?&lt;br /&gt;java.io.IOException: Cannot run program "ant" (in directory "/home/tomcat/hudson/jobs/&lt;project&gt;/workspace/build")&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then, I got to looking at how to set the default Ant, and I could not for the life of me find the setting anywhere.  This is because, there is NO default that can be changed from within Hudson.&lt;br /&gt;&lt;br /&gt;If you tell Hudson to use the default Ant for a build, then it will use whatever ant it finds on the PATH.  Note that I did not say that Hudson will use whatever ANT_HOME points to.  Hudson must be able to find the ant command on the PATH.&lt;br /&gt;&lt;br /&gt;In our case, Hudson runs as the user 'tomcat.'&lt;br /&gt;&lt;br /&gt;So, if I wanted to use the default Ant for a build, I would typically solve this by setting both the ANT_HOME and PATH environment variables for the tomcat user.  I would set ANT_HOME to the Ant installation that I wish to use as default, and I would then add $ANT_HOME/bin to the PATH environment variable.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What I Actually Did&lt;/h3&gt;&lt;br /&gt;Since I really didn't care to go to all that trouble of setting environment variables, I just used the named Ant instance that I had already configured in Hudson.  We do not have a default Ant available to Hudson, and it's not a problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-6056833472315251200?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/6056833472315251200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=6056833472315251200' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6056833472315251200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6056833472315251200'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/01/hudson-default-anth.html' title='Hudson Default Ant'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-4422845835443058365</id><published>2009-01-21T08:56:00.000-08:00</published><updated>2009-01-21T09:07:57.566-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Hudson Gets an AccessControlException when starting on Ubuntu Tomcat</title><content type='html'>With fresh install of Ubuntu 8.10 I grabbed Tomcat 6 from Synaptic.  Then, I dropped the hudson.war into the Tomcat webapps directory, and was greeted with an AccessControlException and a Hudson that would not start.  &lt;br /&gt;&lt;br /&gt;This is because on Ubuntu, Tomcat default installs with the Tomcat Security Manager enabled.  This is probably a good thing for many installs of Tomcat, but it interferes with Hudson.  When we finally found the problem, we took the lazy road and disabled the Tomcat Security.  Depending on your install, this may be an unsafe decision.  I would check the &lt;a href="http://tomcat.apache.org/"&gt;Tomcat documentation&lt;/a&gt; before doing this if your server is externally exposed.  In our environment, the build server is on a completely trusted network.  So, we didn't care much.&lt;br /&gt;&lt;br /&gt;Here is the stack trace that is displayed when first trying to browse to the Hudson app:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;HTTP Status 500 -&lt;br /&gt;&lt;br /&gt;type Exception report&lt;br /&gt;&lt;br /&gt;message&lt;br /&gt;&lt;br /&gt;description The server encountered an internal error () that prevented it from fulfilling this request.&lt;br /&gt;&lt;br /&gt;exception&lt;br /&gt;&lt;br /&gt;javax.servlet.ServletException: Error instantiating servlet class org.kohsuke.stapler.Stapler&lt;br /&gt; org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)&lt;br /&gt; org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)&lt;br /&gt; org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)&lt;br /&gt; org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)&lt;br /&gt; org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)&lt;br /&gt; org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)&lt;br /&gt; java.lang.Thread.run(Thread.java:636)&lt;br /&gt;&lt;br /&gt;root cause&lt;br /&gt;&lt;br /&gt;java.lang.ExceptionInInitializerError&lt;br /&gt; org.apache.commons.beanutils.ConvertUtilsBean.&lt;init&gt;(ConvertUtilsBean.java:130)&lt;br /&gt; org.kohsuke.stapler.Stapler.&lt;clinit&gt;(Stapler.java:659)&lt;br /&gt; sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)&lt;br /&gt; sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)&lt;br /&gt; sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)&lt;br /&gt; java.lang.reflect.Constructor.newInstance(Constructor.java:532)&lt;br /&gt; java.lang.Class.newInstance0(Class.java:372)&lt;br /&gt; java.lang.Class.newInstance(Class.java:325)&lt;br /&gt; org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)&lt;br /&gt; org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)&lt;br /&gt; org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)&lt;br /&gt; org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)&lt;br /&gt; org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)&lt;br /&gt; org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)&lt;br /&gt; java.lang.Thread.run(Thread.java:636)&lt;br /&gt;&lt;br /&gt;root cause&lt;br /&gt;&lt;br /&gt;java.security.AccessControlException: access denied (java.util.PropertyPermission org.apache.commons.logging.LogFactory.HashtableImpl read)&lt;br /&gt; java.security.AccessControlContext.checkPermission(AccessControlContext.java:342)&lt;br /&gt; java.security.AccessController.checkPermission(AccessController.java:553)&lt;br /&gt; java.lang.SecurityManager.checkPermission(SecurityManager.java:549)&lt;br /&gt; java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1302)&lt;br /&gt; java.lang.System.getProperty(System.java:669)&lt;br /&gt; org.apache.commons.logging.LogFactory.createFactoryStore(LogFactory.java:320)&lt;br /&gt; org.apache.commons.logging.LogFactory.&lt;clinit&gt;(LogFactory.java:1725)&lt;br /&gt; org.apache.commons.beanutils.ConvertUtilsBean.&lt;init&gt;(ConvertUtilsBean.java:130)&lt;br /&gt; org.kohsuke.stapler.Stapler.&lt;clinit&gt;(Stapler.java:659)&lt;br /&gt; sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)&lt;br /&gt; sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)&lt;br /&gt; sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)&lt;br /&gt; java.lang.reflect.Constructor.newInstance(Constructor.java:532)&lt;br /&gt; java.lang.Class.newInstance0(Class.java:372)&lt;br /&gt; java.lang.Class.newInstance(Class.java:325)&lt;br /&gt; org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)&lt;br /&gt; org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)&lt;br /&gt; org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)&lt;br /&gt; org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)&lt;br /&gt; org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)&lt;br /&gt; org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)&lt;br /&gt; java.lang.Thread.run(Thread.java:636)&lt;br /&gt;&lt;br /&gt;note The full stack trace of the root cause is available in the Apache Tomcat/6.0.18 logs.&lt;br /&gt;&lt;/clinit&gt;&lt;/init&gt;&lt;/clinit&gt;&lt;/clinit&gt;&lt;/init&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This was fixed by changing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/etc/default/tomcat6&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And setting the following property:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# Use the Java security manager? (yes/no, default: yes)&lt;br /&gt;# WARNING: Do not disable the security manager unless you understand&lt;br /&gt;# the consequences!&lt;br /&gt;#TOMCAT6_SECURITY=yes&lt;br /&gt;TOMCAT6_SECURITY=no&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we left the commented example in place for future reference.  I hope this helps someone else.  Mostly, I'm hoping that by writing this down, I will remember this in the future or at least be able to find the solution quicker.&lt;br /&gt;&lt;br /&gt;Go forth and write tests...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-4422845835443058365?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/4422845835443058365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=4422845835443058365' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4422845835443058365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4422845835443058365'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/01/hudson-gets-accesscontrolexception-when.html' title='Hudson Gets an AccessControlException when starting on Ubuntu Tomcat'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-2807493195260903290</id><published>2009-01-14T04:36:00.000-08:00</published><updated>2009-01-14T04:38:54.712-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Cool Code Snippet Tool</title><content type='html'>Simple post for my own memory:&lt;br /&gt;&lt;br /&gt;The best online code snippet posting tool that I've found is at http://pastebin.com/.  It has great syntax highlighting for a variety of languages (including Groovy) and it is very easy to use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-2807493195260903290?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/2807493195260903290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=2807493195260903290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2807493195260903290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2807493195260903290'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/01/cool-code-snippet-tool.html' title='Cool Code Snippet Tool'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8909288423978522523</id><published>2009-01-07T13:06:00.000-08:00</published><updated>2009-01-08T21:11:22.196-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><title type='text'>Tests Drive Good Design</title><content type='html'>Test-first development leads to better design in the production code.  Specifically, you get much lower coupling (both internally and externally), and you get much higher cohesion. &lt;br /&gt;&lt;br /&gt;For those of you unfamiliar with those two terms, Coupling is tying one class to another.  For instance, if ClassA relies on ClassB to do some work in such a way that a break in ClassB causes unit tests for ClassA to break, that's coupling.  We try to limit coupling so that individual classes are isolated.  We will always be coupling our classes to a degre (if java.lang.String breaks, everything breaks), but we try to keep it to a minimum.  We want classes with low coupling because it is easier to isolate change.&lt;br /&gt;&lt;br /&gt;Cohesion is how well the responsibilities within a class relate to each other.  Highly cohesive classes tend to be small chunks that are easy to understand because they have a single responsibility.  If you are tempted to answer the question, "What does this class do?" by using the word "and" a bunch, then you have a class with low cohesion.  We want classes with high cohesion because they are easier to understand and thus easier to change.&lt;br /&gt;&lt;br /&gt;When you write good unit tests, especially when you write them first, its easy to detect classes that are NOT highly cohesive and have low coupling.  Tests become much more difficult to write when you stray from sound coding practices.  If you weren't writing unit tests, you might be tempted to simply "new up" a dependency.  Testing drives one to inject dependencies to create better seams and better class isolation.&lt;br /&gt;&lt;br /&gt;The bottom line is that testable code is better code.  It is easier to change, easier to understand, and overall easier to support.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8909288423978522523?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8909288423978522523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8909288423978522523' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8909288423978522523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8909288423978522523'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2009/01/tests-drive-good-design.html' title='Tests Drive Good Design'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-9014413205995449541</id><published>2008-12-16T10:54:00.001-08:00</published><updated>2008-12-17T07:17:53.488-08:00</updated><title type='text'>Private Bindings in Guice</title><content type='html'>There are rare occasions when I need to bind something locally in &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice&lt;/a&gt;, but I don't want that binding exposed.  One such time happened today.  Our application uses a Configuration object to hold what we read in from a configuration file.  There is plenty of configuration in that file including database connection information and email configuration for reporting errors.  Various parts of the application need various parts of the configuration, but nothing really needs the whole ball of wax.&lt;br /&gt;&lt;br /&gt;There is, however, one exception to this in our application where a Guice Provider actually does need to have the whole Configuration object.  So, we need to have a singleton Configuration instance bound, but I still don't want that exposed.&lt;br /&gt;&lt;br /&gt;Enter annotated bindings.  Guice allows you to bind the same type more than once and to distinguish the different bindings by adding an annotation.  The annotation gets added to the binding in the module as well as the location where the injection is to occur.  So, in this case, we have a binding and Provider like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bind(Configuration.class).annotatedWith(DontExpose.class).toInstance(privateConfig);&lt;br /&gt;bind(Foo.class).toProvider(FooProvider.class);&lt;br /&gt;&lt;br /&gt;private static class FooProvider implements Provider&lt;Foo&gt; {&lt;br /&gt;  public FooProvider(@DontExpose Configuration config) {&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The binding is placed in the configure() method of the Guide Module, and the FooProvider is a private static within the same Guice Module class.  Unless you take one extra step, however, this binding is still exposed.  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Normally, my binding annotations are publicly defined within the project.  Any class that Guice builds can ask for a Configuration annotated with @DontExpose.  To keep that from happening, we simply define the @DontExpose binding annotation as a private element within the Guice Module.  So, the final module would look something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import com.google.inject.*;&lt;br /&gt;import java.lang.annotation.*;&lt;br /&gt;import org.apache.commons.configuration.*;&lt;br /&gt;&lt;br /&gt;public class TestModuleShouldBeDeleted extends AbstractModule {&lt;br /&gt;&lt;br /&gt;  private final CompositeConfiguration config;&lt;br /&gt;&lt;br /&gt;  public TestModuleShouldBeDeleted(CompositeConfiguration config) {&lt;br /&gt;    this.config = config;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  protected void configure() {&lt;br /&gt;    bind(Configuration.class).annotatedWith(DontExpose.class).toInstance(config);&lt;br /&gt;    bind(Foo.class).toProvider(FooProvider.class);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;  @Target( { ElementType.FIELD, ElementType.PARAMETER })&lt;br /&gt;  @BindingAnnotation&lt;br /&gt;  private @interface DontExpose {&lt;br /&gt;    // marker annotation&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private static class FooProvider implements Provider&lt;Foo&gt; {&lt;br /&gt;&lt;br /&gt;    private final Configuration configuration;&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    public FooProvider(@DontExpose&lt;br /&gt;    Configuration configuration) {&lt;br /&gt;      this.configuration = configuration;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public Foo get() {&lt;br /&gt;      return new Foo(configuration.getString("foo.value"));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, the binding to Foo is exposed (as we want it to be), but the binding to the Configuration is not.  This isn't a pattern I use very often, but it was useful today.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-9014413205995449541?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/9014413205995449541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=9014413205995449541' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/9014413205995449541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/9014413205995449541'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/12/private-bindings-in-guice.html' title='Private Bindings in Guice'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-5069044088818400672</id><published>2008-12-15T12:42:00.001-08:00</published><updated>2008-12-15T13:14:37.650-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>Why I Don't Use "Given, When, Then"</title><content type='html'>In &lt;a href="http://dannorth.net/introducing-bdd/"&gt;Introducing BDD&lt;/a&gt;, Dan North states that he and Chris Matts were trying to develop a template that, "had to be loose enough that it wouldn’t feel artificial or constraining to analysts but structured enough that we could break the story into its constituent fragments and automate them."  This gave birth to Given, When, Then syntax.  One example that is given in the article is:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Given&lt;/em&gt; the account is in credit&lt;br /&gt;&lt;em&gt;And&lt;/em&gt; the card is valid&lt;br /&gt;&lt;em&gt;And&lt;/em&gt; the dispenser contains cash&lt;br /&gt;&lt;em&gt;When&lt;/em&gt; the customer requests cash&lt;br /&gt;&lt;em&gt;Then&lt;/em&gt; ensure the account is debited&lt;br /&gt;&lt;em&gt;And&lt;/em&gt; ensure cash is dispensed&lt;br /&gt;&lt;em&gt;And&lt;/em&gt; ensure the card is returned&lt;br /&gt;&lt;br /&gt;This certainly has structure.  But, I personally feel this is still a bit too artificial.  Perhaps it is the large amount of content related to the context (account is in credit, the card is valid, the dispenser contains cash).  I try to avoid specifying behaviors that have this many moving parts.  I would prefer to see a behavior like:&lt;br /&gt;&lt;br /&gt;The dispenser when the account is in credit should dispense cash.&lt;br /&gt;The dispenser when the account is in credit should debit the account.&lt;br /&gt;The dispenser when all transactions are complete should ensure the card is returned&lt;br /&gt;&lt;br /&gt;I want to read sentences.  When possible, I want to read short sentences.  Given When Then generates a matrix of sentences to be parsed.  GWT also saves some space in the report, but I gladly give that space back to have behavioral sentences that are easier to read quickly.&lt;br /&gt;&lt;br /&gt;So, how do I keep the language regular and well-formed?  The answer shows up more in the source code of the behvaiors than in the report.  So, I might write the following behavior using EasySpec (in Groovy):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@EasySpec(interest='The dispenser')&lt;br /&gt;class Dispenser_happy_path_Test extends GroovyTestCase() {&lt;br /&gt;&lt;br /&gt;def account = new Account(balance:1000)&lt;br /&gt;def dispenser = new Dispenser(available:5000)&lt;br /&gt;&lt;br /&gt;@Context('when the account is in credit and the dispenser has cash')&lt;br /&gt;public void setUp() {&lt;br /&gt;  dispenser.dispense(account, 100)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Behavior&lt;br /&gt;void test_should_debit_the_account() {&lt;br /&gt;  assertEquals(900, account.balance)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Behavior&lt;br /&gt;void test_should_dispense_the_requested_cash() {&lt;br /&gt;  assertEquals(100, dispenser.totalDespensed)&lt;br /&gt;  assertEquals(4900, dispenser.available)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Behavior&lt;br /&gt;void test_should_return_the_card() {&lt;br /&gt;  assertTrue(dispenser.lastCardReturned)&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Upon running the EasySpec report, the user will get the following behaviors:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;The dispenser when the account is in credit and the dispenser has cash should debit the account&lt;br /&gt;&lt;br /&gt;The dispenser when the account is in credit and the dispenser has cash should dispense the requested cash&lt;br /&gt;&lt;br /&gt;The dispenser when the account is in credit and the dispenser has cash should return the card&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Easy Spec actually generates reports with nice formatting &lt;a href="http://testinfected.dyndns.org/easyspec/java-example-report/"&gt;like this&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Perhaps all of this is just personal preference.  But, I do find it easy to go back to old specifications and understand what is going on.  Language and fluency are important.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-5069044088818400672?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/5069044088818400672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=5069044088818400672' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5069044088818400672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5069044088818400672'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/12/why-i-dont-use-given-when-then.html' title='Why I Don&apos;t Use &quot;Given, When, Then&quot;'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-2772016342982395389</id><published>2008-12-15T12:31:00.000-08:00</published><updated>2008-12-15T12:42:06.853-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>You Might Be A Behaviorist...</title><content type='html'>Are you doing BDD?  This is a question I've often heard at recent conferences.  As far as I can tell, most people that have looked at BDD concepts are quite sure if they're doing BDD or not.  Here are some sign that you might be a Behaviorist:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;You talk more about executable specifications and less about "tests."&lt;br /&gt;&lt;/li&gt;&lt;li&gt;You write your specifications before you write the production code.&lt;/li&gt;&lt;li&gt;You place high value on natural language in your tests.&lt;/li&gt;&lt;li&gt;You can generate a system-wide report that shows system behaviors in natural language.  Bonus points if you do this with every build.&lt;/li&gt;&lt;li&gt;You write your specifications or tests with exactly one context per test class.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Not everyone that is doing these things would classify their projects as using BDD.  And, not everyone that says they're using BDD is applying these concepts.  But, I think that in the majority of cases you will find a majority of these practices in some form or another.&lt;br /&gt;&lt;br /&gt;If I have missed anything, Dear Reader, please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-2772016342982395389?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/2772016342982395389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=2772016342982395389' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2772016342982395389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2772016342982395389'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/12/you-might-be-behaviorist.html' title='You Might Be A Behaviorist...'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-5071552106992452399</id><published>2008-12-15T08:37:00.000-08:00</published><updated>2009-01-08T22:53:50.627-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>My English Teacher Would Be Proud -- Proper Language Is Still Important</title><content type='html'>My high school had one English teacher that was dreaded by all, Mrs. Koch.  Mrs. Koch's classes were known to be tough.  Most of my friends were accustomed to getting high grades, but this didn't happen too often in Mrs. Koch's classes.  Over the course of two semesters, one student got an 'A' in one semester.  Mrs. Koch took for granted that we knew the basics that we were supposed to know.  For written assignments, she assumed that everything would be spelled correctly and there would be zero grammatical errors.  Assignments were graded for content, but grammatical errors caused sever markdowns in one's grade.  Language was important.&lt;br /&gt;&lt;br /&gt;I am thankful to Mrs. Koch for nurturing a strong sense of grammar in me.  Perhaps this is what I have always liked the strict syntax of programming languages.  This may also explain why I like Behavior Driven Development so much.  Language was critical in Mrs. Koch's class, and language is critical to understanding business software.&lt;br /&gt;&lt;br /&gt;BDD brings language into what I believe is its proper place -- the forefront.  Language allows developers to understand the business.  Language allows the development team to communicate with the project sponsors and domain experts.  The more prominent, clear, and accessible our language is, the more readily we understand each other.  The more accessible the language is in the code base, the easier it is to understand what we are doing and why we are doing it.&lt;br /&gt;&lt;br /&gt;This is why I like BDD so much.  When I read through specifications, I can understand what the system does.  The more natural the language is, the faster I can stop thinking about syntax and start thinking about the correctness of the system.  Natural language also helps to engage the non-developers on the team.  While I've watched our project managers look at Java code and guess about what the system is doing, its much easier for us to have a conversation without Java language constructs getting in the way.  Likewise, the less we talk about exceptions, try/catch blocks, and if-else statements, the better.  Instead, we prefer discussing how the system should and should not behave under certain conditions.&lt;br /&gt;&lt;br /&gt;Case in point:  Instead of, "The protected area should thrown an exception for unauthenticated users," I would prefer to say, "The protected page should require the user to be logged in."  We shouldn't have to acclimate the business types to programmer speak.&lt;br /&gt;&lt;br /&gt;Clear language also helps us identity when the design is going astray.  One simple word is often a clue to me that a class has too much responsibility.  That magic word is, "and."  Here's an example:&lt;br /&gt;&lt;br /&gt;Lets assume that we're developing a console application that takes in a relatively complex configuration file.  The customer has told us that, when the configuration is bad, he wants to be notified in a variety of ways.  Sometimes this process will be run manually, and he would like the operator to receive immediate console output for bad configuration.  Sometimes, the process is launched automatically and unattended, so he would like configuration problems to be emailed as well.  For a final good measure, he has also requested that problems be logged to the logging system we have chosen for the project.  We'll assume that the logging and email services live behind a nice interface that is easy to test.  We might, then, get a specification that looks like this&lt;br /&gt;&lt;br /&gt;&lt;code&gt;The ConfigurationHandler, when some configuration properties are missing and logging is configured and email is configured should log an error for the missing properties and send an email for the error and write an error message to the console.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Assuming that our logging and email systems are properly testable (injected somehow), the actual calls to those services could be a pretty small footprint in the production code.  However, this is too much responsibility for the ConfigurationHandler.  We see it logging, sending email, printing to the console and killing the process somehow.  There are lots of "ands" in the specification indicating that perhaps too much responsibility has been given to the ConfigurationHandler.&lt;br /&gt;&lt;br /&gt;If we look at the behaviors shown, they are all about reporting the error.  This is when we notice that, perhaps what we need is one more concept called the ErrorService.  We can hide all the emailing and logging behind that.  So, we break out a new class and a new interface and we end up with the following specifications:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;The Configuration Handler, when some configuration properties are missing should report the missing properties to the ErrorService.&lt;br /&gt;&lt;br /&gt;The ErrorService should forward errors to the log file, email, and console.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;There are still some "and's" there, but the responsibilities are better broken down.&lt;br /&gt;&lt;br /&gt;Language is critical to understanding software.  BDD helps bring language into more prominence.  What does the language of your specifications tell you?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-5071552106992452399?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/5071552106992452399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=5071552106992452399' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5071552106992452399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5071552106992452399'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/12/my-english-teacher-would-be-proud.html' title='My English Teacher Would Be Proud -- Proper Language Is Still Important'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8148723054861366956</id><published>2008-12-15T08:08:00.000-08:00</published><updated>2008-12-15T08:33:43.561-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>Package Properly:  Where Your Tests Live Is Important</title><content type='html'>About nine months ago, our team decided to start using &lt;a href="http://dannorth.net/introducing-bdd/"&gt;Behavior Driven Design&lt;/a&gt;.  Rather than making big changes in the build system to bring in a BDD framework, I put together a BDD reporting framework called &lt;a href="http://code.google.com/p/easyspec/"&gt;EasySpec&lt;/a&gt; that allowed us to continue to leverage JUnit.  One of our goals in trying BDD was to really push the limits of natural language in testing and determine what the limits were for BDD.  We ran into limits with our mocking framework, but &lt;a href="http://code.google.com/p/mockito/"&gt;Mockito&lt;/a&gt; solved those problems for us (more on that in a future post).&lt;br /&gt;&lt;br /&gt;One thing that we found was that BDD works pretty well for all levels of testing.  Many of the BDD practitioners will only use BDD for higher level integration testing.  However, I've found that I really like it for unit-level testing as well.  Language is important regardless of where.  It is certainly nice to understand system behavior in the large, but as a developer I need to understand behavior in the small as well.&lt;br /&gt;&lt;br /&gt;We package our unit-level tests in a test source tree that parallels the production code source tree.  So, if I am spec'ing out the com.company.foo.NewFoo, then the production source lives in myProject/src/com/company/foo/NewFoo.java and the first spec will end up in myProject/test/com/company/foo/NewFoo_when_X_Test.java.&lt;br /&gt;&lt;br /&gt;One unintended advantage of staying with JUnit and EasySpec was that our new BDD tests landed right next to the old JUnit tests.  The subconscious communication that this packaging created was wonderful.  It removes the step of questioning where the next test or spec should live.  The next spec goes into the parallel package.  This also communicates that we are going to be driving the same requirements with BDD that we drove previously using TDD methods.  In other words, we aren't just writing larger integration tests with BDD.  We are writing as much as possible using BDD because again, langauge is paramount to understanding the system.&lt;br /&gt;&lt;br /&gt;How do you package your specs?  And, have you pushed the limits to find out how low-level you can drive BDD concepts into your design?  I love designing in the small with BDD.  My production code is better, and the specification artifacts are wonderful.  When supporting code writting six months ago, I find it much easier to understand the system if we have EasySpec specifications rather than JUnit tests -- regardless of the level of abstraction under test.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8148723054861366956?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8148723054861366956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8148723054861366956' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8148723054861366956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8148723054861366956'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/12/package-properly-where-your-tests-live.html' title='Package Properly:  Where Your Tests Live Is Important'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-7255748927048286162</id><published>2008-12-11T23:12:00.001-08:00</published><updated>2008-12-14T14:51:44.536-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='EasySpec'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Publishing Build Artifacts With Hudson</title><content type='html'>Tonight, I found yet another reason to love the Hudson continuous integration server.  Publishing build artifacts is way easy.  What's better, the latest artifacts are available under a static link.  So, it's easy to set a bookmark and always have the latest output available without digging through the server.&lt;br /&gt;&lt;br /&gt;I've setup publicly visible builds for &lt;a href="http://testinfected.dyndns.org/hudson/job/Easy%20Spec/"&gt;EasySpec&lt;/a&gt; along with the &lt;a href="http://testinfected.dyndns.org/hudson/job/Easy%20Spec%20Groovy%20Example/"&gt;Groovy example&lt;/a&gt; and &lt;a href="http://testinfected.dyndns.org/hudson/job/Easy%20Spec%20Java%20Example/"&gt;Java example&lt;/a&gt; projects.  All of these projects use &lt;a href="http://code.google.com/p/easyspec/"&gt;EasySpec&lt;/a&gt; for Behavior Driven Design.  A major component of BDD is having the latest behavior report available.  So, I have included a build target named "report" in each of these projects.  This target simply runs EasySpec to generate the behavior report into a known location in the workspace.&lt;br /&gt;&lt;br /&gt;Let's take the Groovy example and walk through it.  After every checkin, the Hudson build does&lt;br /&gt;&lt;div style="margin-left: 1em;"&gt;&lt;code&gt;gant clean test report&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;This cleans the working copy, then compiles everything, runs the tests, and finally generated the EasySpec report.  Relative to the working copy base, the report ends up in build_output/reports/EasySpec/index.html&lt;br /&gt;&lt;br /&gt;To publish this report, only a couple of simple steps are required.  First, go to the project configuration page for the build that you wish to publish artifacts from.  In this case, that's Hudson/GroovyExample/Configure.  Then, find the checkbox, "Post-build Actions / Archive the artifacts"  Enter the relative path of the artifacts that you wish to publish.  In this case, that's "&lt;br /&gt;build_output/reports/EasySpec/index.html"  Click "Save" and it's all done.&lt;br /&gt;&lt;br /&gt;Now, everytime this project builds successfully, the latest EasySpec report is published to a constant URL.  If you want, &lt;a href="http://testinfected.dyndns.org/hudson/job/Easy%20Spec%20Groovy%20Example/lastSuccessfulBuild/artifact/easyspec_reports/index.html"&gt;checkout the latest example EasySpec report&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I love Hudson&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-7255748927048286162?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/7255748927048286162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=7255748927048286162' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/7255748927048286162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/7255748927048286162'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/12/publishing-build-artifacts-with-hudson.html' title='Publishing Build Artifacts With Hudson'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-919532507459217856</id><published>2008-11-30T22:57:00.000-08:00</published><updated>2008-11-30T22:59:44.957-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='EasySpec'/><title type='text'>EasySpec Continuous Integration Server Visible</title><content type='html'>I have made available a Hudson build for EasySpec.  This turned out to be a fun exercise in setting up Hudson to build a GoogleCode project and a Gant project all in one.  The Hudson plug-ins for GoogleCode and Gant both helped a great deal.&lt;br /&gt;&lt;br /&gt;URL:  hudson.testinfected.net&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-919532507459217856?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/919532507459217856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=919532507459217856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/919532507459217856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/919532507459217856'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/11/easyspec-continuous-integration-server.html' title='EasySpec Continuous Integration Server Visible'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-2113116996498253704</id><published>2008-11-30T21:15:00.000-08:00</published><updated>2008-11-30T21:23:11.314-08:00</updated><title type='text'>Hudson and .Net</title><content type='html'>Hudson has to be the easiest CI server I've ever worked with.  And, based on the number of plug-ins and the rate at which plug-ins are being developed, it must have a pretty easy plug-in model.  Apparently, the &lt;a href="http://gant.codehaus.org/"&gt;gant&lt;/a&gt; plug-in took about an hour &lt;a href="http://weblogs.java.net/blog/kohsuke/archive/2007/07/hudson_gant_plu.html"&gt;to write&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Configuration is very easy as well.  I don't believe I've ever had to dig into the actual configuration files for different builds and tasks.  The web front-end for configuration is great.  I also like the ability to watch the console during a build and all of the build status tracking and archiving.  There are MANY more great plug-ins available, many of which would be applicable to .Net projects as well as Java projects.&lt;br /&gt;&lt;br /&gt;Although I'm not doing much .Net development right now, if I was, I would probably be tempted to setup a Hudson CI server to see if I liked it better than CC.Net.  For those readers that are interested in seeing more about using Hudson with .Net, Redsolo has a pretty &lt;a href="http://redsolo.blogspot.com/2008/04/guide-to-building-net-projects-using.html"&gt;comprehensive guide &lt;/a&gt;to getting started.&lt;br /&gt;&lt;br /&gt;Check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-2113116996498253704?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/2113116996498253704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=2113116996498253704' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2113116996498253704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2113116996498253704'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/11/hudson-and-net.html' title='Hudson and .Net'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-764179773645206655</id><published>2008-08-28T20:06:00.000-07:00</published><updated>2008-08-28T20:20:27.421-07:00</updated><title type='text'>GMail + Address - Why Duplicated Logic Is Still A Bad Idea</title><content type='html'>If you use GMail, you probably already know that you have an infinite number of addresses with a single account.  You can add periods wherever you like in the address.  You can also add tags to the address using the '+' symbol.  So, foobar@gmail.com, foo.bar@gmail.com, fo.obar+baz@gmail.com all go to the same place.&lt;br /&gt;&lt;br /&gt;I like using the '+' tags when giving out my email to automated systems and signups.  This makes it easy to determine if someone is handing out my address for spam when I haven't agreed to that.&lt;br /&gt;&lt;br /&gt;Here's the duplicated logic part:&lt;br /&gt;&lt;br /&gt;So, a while back I activated a subscription for MSDN.  I used my.address+msdn@gmail.com for the email address.  Today, I needeed to download something, and I went to login again, and the system is behaving like I don't remember the password.  This is possible, but unlikely since the passwords that I tend to use (1) I remember, and (2) fit most all password schemes.  However, I conceded that, perhaps, I don't remember the password.  When I go to enter the email address for password retrieval, I get a validation error stating that the email address that I entered is malformed.  Funny, MSDN didn't have any trouble sending the email to that address.  I tried with the +msdn, and of course, that yielded a validation error stating that the email address was not in the system.&lt;br /&gt;&lt;br /&gt;And, yes, I did go back to the confirmation email, and they DID send it to the ...+msdn@gmail.com address.  So, that is, in fact, the address that I registered with.&lt;br /&gt;&lt;br /&gt;It's obvious what's going on here.  The registration site gleefully accepted an email address that the password retrieval site refuses to accept as a well-formed address.  The logic for what constitutes an email address has been duplicated.  Perhaps at some point they were the same.  The registration site may have been "enhanced" to allow the '+' addresses, or perhaps the lost password site was "fixed" to only allow certain formats of email address.  Regardless, it now rests as one system with different rules for what is and is not valid. &lt;br /&gt;&lt;br /&gt;Furthermore, this leads me to suspect that the login site actually shares the same rules with the lost password site.  Meaning, I was able to register with an email address that I cannot login with.&lt;br /&gt;&lt;br /&gt;Looks like I'll have to talk with a human to get this sorted out tomorrow.  Figures that I would find it thirty minutes after everyone goes home.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-764179773645206655?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/764179773645206655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=764179773645206655' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/764179773645206655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/764179773645206655'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/08/gmail-address-why-duplicated-logic-is.html' title='GMail + Address - Why Duplicated Logic Is Still A Bad Idea'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-998340089650642604</id><published>2008-06-28T21:34:00.000-07:00</published><updated>2008-06-28T21:53:01.181-07:00</updated><title type='text'>How Well Do You Know Your Tool?</title><content type='html'>Have you ever used a great tool?  I've been doing some woodworking lately.  So, I've been thinking a bunch about tools.  There is nothing like having a &lt;span style="font-style: italic;"&gt;good&lt;/span&gt; tool when you need it.  Among tradesmen, tools (and tool brands) can evoke a great deal of passion.  You may have know a "DeWalt guy" or a "Matco" lover. &lt;br /&gt;&lt;br /&gt;My grandfather was a very skilled woodworker.  He took a great deal of pride in crafting fine pieces of furniture that were beautifully finished.  My grandfather was a Craftsman guy.  Even when offered more expensive tools, he preferred to work with Craftsman.  Perhaps the source of his passion was the good service he got from the local Sears, or perhaps it was because the tools had never let him down.  Regardless of why, he was passionate about his tools.&lt;br /&gt;&lt;br /&gt;Software development tools are no different.  One need look no further than the vi / emacs wars fought at countless water coolers (to this day) to see the passion that one can have in a development tool.  In Java-land, you may be an Eclipse or IntelliJ devotee.   In .Net, you may insist on running ReSharper or CodeRush.  All of this passion is useless without one critical component...&lt;br /&gt;&lt;br /&gt;How well do you know your IDE?  When was the last time that you looked through the feature shortcuts?  When was the last time that you looked through release notes for new versions?  What about learning keyboard shortcuts?&lt;br /&gt;&lt;br /&gt;I primarily learn new features two ways.  I pick up tricks from my teammates when pair programming.  Sometimes, I learn things completely by accident.  Every once in a while, I fat-finger a keyboard shortcut, and something really cool happens.  Typically, it's not a feature that I want at the time, but it's new to me.  To help me remember it, I will practice it a few times, and share the new information with the rest of the team.&lt;br /&gt;&lt;br /&gt;Take some time and read up on your IDE.  Good tools are useless if you swing everything like a hammer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-998340089650642604?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/998340089650642604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=998340089650642604' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/998340089650642604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/998340089650642604'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/06/how-well-do-you-know-your-tool.html' title='How Well Do You Know Your Tool?'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-7621836187131120484</id><published>2008-06-11T12:00:00.000-07:00</published><updated>2008-06-11T12:05:39.333-07:00</updated><title type='text'>Running Fitnesse Tests</title><content type='html'>It is possible to execute a &lt;a href="http://www.fitnesse.org/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;FitNesse&lt;/span&gt;&lt;/a&gt; page as a test, &lt;span style="font-style: italic;"&gt;even when it is not marked as a test&lt;/span&gt;.  This is a good thing.  Say that you have a page that resides at:&lt;br /&gt;&lt;br /&gt;http://localhost:8181/MySuite.MyTest&lt;br /&gt;&lt;br /&gt;You can simply execute that test by appending "?test" to the end of the URL.  Likewise, you can execute the page as a suite by placing "?suite" at the end of the URL.&lt;br /&gt;&lt;br /&gt;In our project, we have some pages that are common to all tests.  In order to prevent those pages being executed as tests, we changed the page property to indicate that they are not tests.  However, it is &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;occasionally&lt;/span&gt; useful to execute those pages by themselves for debugging purposes.  Rather than going through the annoyance of setting the "Test" property and hoping that I remember to clear it, I can just append the magic text to the end of the URL, and I'm off to the races.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-7621836187131120484?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/7621836187131120484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=7621836187131120484' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/7621836187131120484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/7621836187131120484'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/06/running-fitnesse-tests.html' title='Running Fitnesse Tests'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-4744626116762403227</id><published>2008-05-30T16:44:00.000-07:00</published><updated>2008-05-30T16:48:02.572-07:00</updated><title type='text'>Agile Austin Open Space</title><content type='html'>The Agile Austin Open Space kicks off this evening with agenda and topic setting.  You can find the proceedings documented on the wiki at:  &lt;a href="http://openspace.agileaustin.org/"&gt;openspace.agileaustin.org&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I will be blogging about proceedings as I see things interesting.  Be sure to watch the wiki.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-4744626116762403227?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/4744626116762403227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=4744626116762403227' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4744626116762403227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4744626116762403227'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/05/agile-austin-open-space.html' title='Agile Austin Open Space'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-3143789778464349068</id><published>2008-05-28T20:41:00.000-07:00</published><updated>2008-05-28T21:08:16.215-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>Why Behavior Driven Development?</title><content type='html'>Two years ago, I became completely test-infected.   I hate writing implementation code without writing the test first.  Then, about six months ago, I was introduced to Behavior Driven Development (BDD).  I liked what I saw, but I really didn't see any tools that I wanted to bring into our build system.  The last thing that I wanted to introduce to the company was another test framework.  JUnit was meeting our needs  fairly well, and we were already using FitNesse on our team whereas the rest of the company was not.  We didn't want to add another tool on top of that.&lt;br /&gt;&lt;br /&gt;Then, a few months ago, I saw Scott Bellware give a talk on BDD and saw how he simply did BDD within a normal unit-testing framework and used .Net attributes to markup the tests with the BDD language.  I liked what I saw.  That night, I started a similar tool for JUnit called &lt;a href="http://code.google.com/p/easyspec/"&gt;EasySpec&lt;/a&gt;.  The tool still has some kinks to work out, but BDD has definitely brought some interesting insights into how we design our tests.&lt;br /&gt;&lt;br /&gt;So, why BDD?  At first, it was simply a trial of a style that seemed to do a good job of pulling out the &lt;a href="http://steve.emxsoftware.com/Domain+Driven+Design/DDD+Ubiqitous+Language"&gt;Ubiquitous Language&lt;/a&gt;.  Now that we have been using the techniques for about three months, I must say that I really like using BDD for creating software -- especially around the Domain Model.&lt;br /&gt;&lt;br /&gt;BDD cleans up the language and gets the developers talking more about behaviors and less about implementation.  Where, in the past, I might have been tempted to write a test with a method name like, "the_service_should_throw_an_exception_if_the_user_is_not_authenticated," I would now write that same test with a name like, "the_service_should_require_authenticated_users."  Internally, the test would still be implemented in the same fashion, with probably the same code.  However, language is important.  It's important for the developers to think in the domain rather than hiding in the implementation layer.  If I'm interested in the details of how the service requires authenticated users, then I can look at the details of the test (which should still be cleanly written) and see that in fact, the service will throw an exception if it somehow is handed an unauthenticated user.&lt;br /&gt;&lt;br /&gt;This is merely one example.  Keep a watch here for more information about BDD and why I'm hooked.  Also, I should be putting some polish into EasySpec in the next week or two so that it's more user-friendly.  If you're already using JUnit, and you want to try out BDD, take a look at EasySpec.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-3143789778464349068?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/3143789778464349068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=3143789778464349068' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3143789778464349068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3143789778464349068'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/05/why-behavior-driven-development.html' title='Why Behavior Driven Development?'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-3743343836951348458</id><published>2008-03-14T21:55:00.000-07:00</published><updated>2008-06-12T20:32:22.256-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>EasySpec in the works</title><content type='html'>I have started a new project named EasySpec for doing Behavior Driven Development in Java and Groovy.  There is plenty of functionality that I want to add soon, but the core of it is available (as a .jar).  The project page on GoogleCode can be found at &lt;a href="http://code.google.com/p/easyspec/"&gt;http://code.google.com/p/easyspec/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Our team has been using EasySpec for guiding our behavioral specifications for the last three months.  I am hooked.  If you want specific examples, leave some feedback here.  I should be finishing up the current feature development within the next day or so.  Then, I will be finishing some examples to be posted by the end of next week.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-3743343836951348458?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/3743343836951348458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=3743343836951348458' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3743343836951348458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3743343836951348458'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/03/easyspec-in-works.html' title='EasySpec in the works'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8939780583086536556</id><published>2008-03-14T10:07:00.001-07:00</published><updated>2008-03-14T21:26:59.924-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Guice'/><title type='text'>Create a Guice Injector Using Multiple Modules</title><content type='html'>This is a very short note, but I spent too much time on Google looking for this answer and I wanted to provide a concise bit of information about it.  It has recently become necessary for us to separate our Guice configuration into multiple Guice modules.  We tend to have some dependencies that are project specific and others that typically remain constant from one project to another.  I didn't see mention of this in the Guice guide.  So, here is the information:&lt;br /&gt;&lt;br /&gt;Guice.createInjector() can take a variable number of Modules.  So, it is trivial to do this:&lt;br /&gt;&lt;br /&gt;Guice.createInjector(myProjectDependencies, myDatabaseDependencies) and so on.&lt;br /&gt;&lt;br /&gt;This will really help to prevent duplicating binding logic from one project to the next.  We are separating our data-tier module out from project-specific bindings.&lt;br /&gt;&lt;br /&gt;Again, all of this is trivial, but since I didn't readily find the answer on Google earlier, I wanted to put it out.&lt;br /&gt;&lt;br /&gt;Another interesting note is that it is possible to bind to classes in module A that need bindings from module B while at the same time bind to classes in module B that need bindings from module A.  Very slick.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8939780583086536556?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8939780583086536556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8939780583086536556' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8939780583086536556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8939780583086536556'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/03/create-guice-injector-using-multiple.html' title='Create a Guice Injector Using Multiple Modules'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8394017255586069048</id><published>2008-02-08T09:45:00.000-08:00</published><updated>2008-02-11T09:35:32.382-08:00</updated><title type='text'>How To Quickly Frustrate Future Developers</title><content type='html'>Simply put, if you want to frustrate your teammates, let your abstractions leak.&lt;br /&gt;&lt;br /&gt;Have a production implementation of an interface with stubbed calls?  How about a subclass that neuters parent-class functionality?  If you do, you may be well on your way to setting a trap for future developers (quite possibly your future-self).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Interfaces&lt;/span&gt;&lt;br /&gt;If you really don't need all the methods on an interface, then the interface is too big and should be broken out.  Here's a contrived example.  Consider what an IDaddy interface might look like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interface IDaddy {&lt;br /&gt;  public void changeDiaper(Baby baby);&lt;br /&gt;  public void procreate(IMommy mommy);&lt;br /&gt;  //More methods, but significantly less than the IMommy interface.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This interface had better have a singleton production interface.  Otherwise, other implementations of IDaddy that implement the procreate(IMommy) will have some serious 'splaining to do!  (IMommy better be a singleton as well, or the IDaddy is in big trouble...).&lt;br /&gt;&lt;br /&gt;Anyway, there are certainly uses for having someone other than Daddy change the baby diaper.  Perhaps a better set of interfaces would be:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interface IBabySitter {&lt;br /&gt;  public void changeDiaper(Baby baby);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface IDaddy extends IBabySitter {&lt;br /&gt;  public void procreate(IMommy mommy);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now we can have several implementations that can change the baby diaper without creating family strife!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Subclasses&lt;/span&gt;&lt;br /&gt;Just ran into this class today:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class UnknownColumnNameException extends RuntimeException {&lt;br /&gt;&lt;br /&gt;  private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;  String strColumnName;&lt;br /&gt;&lt;br /&gt;  public UnknownColumnNameException(String colName) {&lt;br /&gt;    strColumnName = colName;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String toString() {&lt;br /&gt;    return super.toString() + " ColumnName = " + strColumnName;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void printStackTrace() {&lt;br /&gt;    System.err.println(" ColumnName = " + strColumnName);&lt;br /&gt;    super.printStackTrace();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String getColumnName() {&lt;br /&gt;    return strColumnName;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For those of you not completely familiar with Java's exceptions, you may not notice what is missing.  In the top level processing, we have a generic, last-ditch catch of all Throwable so that we can dump log files, etc.  This exception has not set any message.  So, when I do an ex.getMessage() in the top-level catch, all I get is null.   Thanks for nuthin'.&lt;br /&gt;&lt;br /&gt;The user has to know about this specific exception type in order to get the useful information back out of it.  Bad, Bad, Bad!  If this pattern was extended, then we'd have to put a catch for each type of exception that just might happen, and pull the specialized information out of each one.  Forget it!&lt;br /&gt;&lt;br /&gt;The fix?  Simply set the message in the subclass.  In this case, this can be done by leaning on the superclass constructor as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class UnknownColumnNameException extends RuntimeException {&lt;br /&gt;  ...&lt;br /&gt;  public UnknownColumnNameException(String colName) {&lt;br /&gt;    super("Could not find column with name '" + colName + "'.");&lt;br /&gt;    strColumnName = colName;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Simple fix.  Great improvement in usability.  Perhaps next time, I won't have to resort to the debugger to know that the input file has a problem.&lt;br /&gt;&lt;br /&gt;What kind of abstraction leaks have you found?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8394017255586069048?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8394017255586069048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8394017255586069048' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8394017255586069048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8394017255586069048'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/02/how-to-quickly-frustrate-future.html' title='How To Quickly Frustrate Future Developers'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8102728707203416837</id><published>2008-02-05T10:05:00.000-08:00</published><updated>2008-02-05T10:37:22.996-08:00</updated><title type='text'>How Can a Simple Code Template Change Make Life Better?</title><content type='html'>Ever felt like making a small change has sent you down a rabbit hole?  I sure have.  Consider the following classes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public interface NotificationService {&lt;br /&gt;  void sendNotification(String user);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Unit {&lt;br /&gt;  private NotificationService notification;&lt;br /&gt;&lt;br /&gt;  public Unit(NotificationService notification) {&lt;br /&gt;    this.notification = notification;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void doSomething(String username) {&lt;br /&gt;    notification.sendNotification(username);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You might write a test to ensure that Unit.doSomething() passes off the username to the NotificationService.sendNotification().  This would be a very simple mock test.&lt;br /&gt;&lt;br /&gt;Now, let's assume that everything shown so far is already under test, 100% coverage.  Requirements have changed, and now when we doSomething(), we should check for pending notifications for that username first.  &lt;br /&gt;&lt;br /&gt;The first change to make would be adding a method to the NotificationService interface:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public interface NotificationService {&lt;br /&gt;  void sendNotification(String user);&lt;br /&gt;  Notifications retrievePendingNotifications(String user);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, we can write a test for the Unit class, using a mock of NotificationService to verify that doSomething() will check for the pending notificiations.  Doing Test-Driven Design, we want to make sure that we are focusing on changing one class at a time.  However, now that we have added retrievePendingNotifications() to the interface without actually implementing that method on the implementing classes, we will have a compile error.&lt;br /&gt;&lt;br /&gt;One choice for getting around this would be to go down the rabbit trail, writing tests for the implementing classes and actually implementing the new method.  Personally, I don't like to do this because it changes my focus.  I would rather first ensure that the caller is correct before worrying about the actual implementation of the interface.&lt;br /&gt;&lt;br /&gt;Most modern IDE's will offer a quick-fix to stub out the implementation of the interface so that things will compile.  The default behavior for this default implementation is typically to return the simplest thing possible.  If the function is void, then the stubbed method does nothing. If the function returns a primitive, say &lt;b&gt;int&lt;/b&gt;, then the IDE will put in something like &lt;b&gt;return&lt;/b&gt; 0; to make things compile.  &lt;br /&gt;&lt;br /&gt;This kind of default stub has already worried me that I will forget to actually do the implementation.  In fact, I have done just that before, sometimes not finding the hole until a day or two later.  At that point, figuring things out sometimes involves going to the debugger to figure out why I'm getting a NullPointerException.&lt;br /&gt;&lt;br /&gt;Enter code templates.  The default implementation can be modified in most IDE's.  Here is a sample of how I changed my code template to prevent this problem in the future:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public Notifications retrievePendingNotifications(String user) {&lt;br /&gt;    throw new NotImplementedException(&lt;br /&gt;      "NotificationServiceImpl.retrievePendingNotifications() not yet implemented.");&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, I don't have to try and keep that little piece of information in my head.  I can rest easy that, if I forget to implement something, it will still fail (hard) during integration testing.  Now, I will know the direct cause of the problem immediately.&lt;br /&gt;&lt;br /&gt;It's amazing to me how this simple change has made me rest so much easier.&lt;br /&gt;&lt;br /&gt;Go forth and write tests!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8102728707203416837?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8102728707203416837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8102728707203416837' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8102728707203416837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8102728707203416837'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/02/how-can-simple-code-template-change.html' title='How Can a Simple Code Template Change Make Life Better?'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-426041960992121914</id><published>2008-01-18T23:26:00.000-08:00</published><updated>2008-01-21T10:11:55.167-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>DRY Groovy, How To Get Groovy To Import A Class Into a Script</title><content type='html'>&lt;span style="font-weight:bold;"&gt;UPDATE:  Read to the bottom to see another way to tackle this problem&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Each time you repeat yourself in code, you may as well leave a bear trap by your desk.  In fact, the bear trap is probably safer for me.  Whenever I see repeated code, I want to poke my eyes out.  I do my best to keep my code &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;dry&lt;/a&gt; whenever reasonable.&lt;br /&gt;&lt;br /&gt;So, when I started writing Groovy scripts, it became obvious pretty quickly that I had some utility classes waiting to break out.  The only problem was, I couldn't find the technique for importing a Groovy class from another file into the current script.  Thanks go to Peter Niederwieser for the solution.&lt;br /&gt;&lt;br /&gt;Here's the setup:&lt;br /&gt;&lt;br /&gt;Two Groovy files:&lt;br /&gt;c:\tools\groovy\myscript.groovy&lt;br /&gt;c:\tools\groovy\MyClass.groovy&lt;br /&gt;&lt;br /&gt;The content of MyClass.groovy:&lt;br /&gt;&lt;pre&gt;class MyClass {&lt;br /&gt;  def howdy() {&lt;br /&gt;    println 'Howdy'&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The content of myscript.groovy:&lt;br /&gt;&lt;pre&gt;new MyClass().howdy()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Super simple.  However, no matter how I tried to run myscript, I got this error message:&lt;br /&gt;&lt;pre&gt;org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,&lt;br /&gt;c:\tools\groovy\myscript.groovy: 1: unable to resolve class MyClass&lt;/pre&gt;&lt;br /&gt;What gives?  The files were right next to each other, but stupid Groovy couldn't find them.  That's when Peter reminded me that groovy will look in the classpath to resolve classes.&lt;br /&gt;&lt;br /&gt;There are two ways (that I know of) to tell Groovy what your classpath is.  You can either indicate it on the command line as in:&lt;br /&gt;&lt;pre&gt;groovy -cp c:\tools\groovy myscript.groovy&lt;/pre&gt;&lt;br /&gt;Or, you can set the CLASSPATH environment variable to include the path where the collaborating class (in this case, MyClass.groovy) lives.&lt;br /&gt;&lt;br /&gt;Using the classpath, you don't even have to keep your script and its dependencies in the same directory.  I simply set my CLASSPATH, and now I'm off to the races.  Now, I keep all my scripts in c:\tools\groovy (which is on my PATH), and my classes in c:\tools\groovy\classes (which is on my CLASSPATH).&lt;br /&gt;&lt;br /&gt;WARNING:  For all of you Windows users out there, the name of the Groovy file IS CASE SENSITIVE!  So, if you want Groovy to find class MyClass, it had better be in something like, %CLASSPATH%\MyClass.groovy.  %CLASSPATH%\myclass.groovy did NOT work for me.  This would make complete sense to me if I were in a Unix environment.  However, I am used to my Windows machines being mostly case insensitive.  This is a bit odd, but understandable I guess.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;UPDATE:&lt;/span&gt;  &lt;a href="http://blackdragsview.blogspot.com/"&gt;Jochen Theodorou&lt;/a&gt; has pointed me in the right direction for another solution that I like better.  You don't have to modify the classpath to cause groovy to find the classes that you are importing.  Instead, you can add load information to your %GROOVY_HOME%\conf\groovy-starter.conf file.  Mine now has these extra lines:&lt;br /&gt;&lt;pre&gt;# load classes for local scripts&lt;br /&gt;load c:/tools/groovy/classes&lt;/pre&gt;&lt;br /&gt;Now, I don't have to keep the CLASSPATH environment variable set and worry about how that interacts with Java.&lt;br /&gt;&lt;br /&gt;There you have it.  Now, you can keep your scripts dry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-426041960992121914?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/426041960992121914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=426041960992121914' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/426041960992121914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/426041960992121914'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/01/dry-groovy-how-to-get-groovy-to-import.html' title='DRY Groovy, How To Get Groovy To Import A Class Into a Script'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-4500122482842249750</id><published>2008-01-14T06:53:00.001-08:00</published><updated>2008-01-14T07:05:03.079-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Mocking Groovy Objects with EasyMock in Java</title><content type='html'>I mentioned before that I needed to do some unit testing of a class that I was targeting in Groovy with come unit tests in Java.  In Java, I am using EasyMock to mock out the collaborators.  I am dealing with one collaborator, an interface, that looks like this (Groovy):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interface FileSystem {&lt;br /&gt;    ...&lt;br /&gt;    def uploadFile(inputStream, destinationPath)&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For the purposes of this unit test, I didn't care what got returned, so I setup the expectation like this (Java):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;desintationFileSystem.uploadFile(streamForFile1, "someDir\\someOtherDir\\file1.jpg");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Running the test, I was greeted with this message:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;java.lang.IllegalStateException: missing behavior definition &lt;br /&gt;  for the preceeding method call &lt;br /&gt;  uploadFile(EasyMock for class java.io.FileInputStream,&lt;br /&gt;    "someDir\someOtherDir\file1.jpg")&lt;br /&gt;    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:27)&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's when I remembered something fundamental to groovy... the 'def' type means variable return type.  For Java, that translates into Object.  To make the test run, I either needed to explicitly change the return type on the interface to be void, or simply setup the EasyMock expectation to return a value.  Since I didn't want to change the interface, I chose to specify the return value in the expectation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-4500122482842249750?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/4500122482842249750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=4500122482842249750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4500122482842249750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4500122482842249750'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/01/mocking-groovy-objects-with-easymock-in.html' title='Mocking Groovy Objects with EasyMock in Java'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-352554751714170984</id><published>2008-01-13T18:49:00.000-08:00</published><updated>2008-01-13T19:07:39.878-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>How to Cure a Groovy Headache with Java</title><content type='html'>There was a time during my college years when I was a full-on caffeine addict.  I remember once during finals consuming around 10 cans of Dr. Pepper per day.  When I decided that I needed to come off the caffeine, I had to use some java (coffee) along the way to avoid the nasty headaches.&lt;br /&gt;&lt;br /&gt;Fast forward a few years, and I've once again use some Java to cure a headache.  However, today's headache was caused by a mixture of concrete classes and Groovy's seeming inability to mock concrete classes.  I wish I knew the Groovy life cycle a bit better to explain exactly why it is that I couldn't mock out java.io.FileInputStream.  Suffice to say, Groovy didn't let me substitute in a closure, I didn't want to use mockFor because there was enough else going on. Additionally, Groovy didn't want to cooperate with the EasyMock classextension for reasons I never could quite figure out.&lt;br /&gt;&lt;br /&gt;In comes the Java.  Since Java and Groovy compile down to the same byte code, testing Groovy with Java is pretty easy.  The final solution that I came up with was writing the implementation in Groovy like I wanted to, and writing the test in Java.  I simply used org.easymock.classextension.EasyMock to do the mocking, and away we went.  This was a nice proof of Java and Groovy living right next to each other and working together.  One of the nice things about having the ability to do the test in Java was proving that, indeed, I had all of the project dependencies that I needed and Groovy just did not like mocking out the class.&lt;br /&gt;&lt;br /&gt;Watch here soon, and I am going to post a cool little tool that I am working on for spiking the project structure for a setup like this.  It's much more stripped down from what Grails will give you.  But, if your looking for directory structure and a simple build.gant, then this may be something to look at.&lt;br /&gt;&lt;br /&gt;Now, where's my decaf coffee?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-352554751714170984?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/352554751714170984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=352554751714170984' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/352554751714170984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/352554751714170984'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/01/how-to-cure-groovy-headache-with-java.html' title='How to Cure a Groovy Headache with Java'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-5175299852669324809</id><published>2008-01-11T14:05:00.000-08:00</published><updated>2008-01-11T14:13:35.717-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><title type='text'>Why Do You Use TDD?</title><content type='html'>After about a year and a half of writing tests before implementation, I'm not sure I will ever go back.  Most people call this "Test-Driven Development."  However, given the benefits that come from working this way, I prefer the term, "Test-Driven Design." &lt;br /&gt;&lt;br /&gt;I use TDD for three reasons - (1) Test-Driven Design forces more loosely coupled code which is much more malleable,  (2) I can detect code smells much faster when classes become difficult to test, and (3) it is easier to know when I'm done writing code.&lt;br /&gt;&lt;br /&gt;The tests are a nice bonus product of designing code this way, but they are, in fact, not as important to me as the loose coupling and general good design that comes out the other end.  When writing tests becomes too difficult, noisy, or lengthy, then something is wrong with the design.  Since tests are in place, refactoring to a better design is easier and generally faster.  So, this too aids in improving the design of the implementation.&lt;br /&gt;&lt;br /&gt;Do the tests get in the way sometimes?  Yes.  However, this is often a test smell.  Perhaps the tests have too much intimate knowledge of the implementation.&lt;br /&gt;&lt;br /&gt;If you have not tried writing tests first, I suggest giving it a go on a simple project.  Better yet, find someone that is already experienced in TDD and do some pair programming.&lt;br /&gt;&lt;br /&gt;Now, go forth and write tests...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-5175299852669324809?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/5175299852669324809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=5175299852669324809' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5175299852669324809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5175299852669324809'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/01/why-do-you-use-tdd.html' title='Why Do You Use TDD?'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-4762192790392735635</id><published>2008-01-08T16:24:00.001-08:00</published><updated>2008-01-08T16:28:53.260-08:00</updated><title type='text'>When Subversion Goes Crazy</title><content type='html'>Recently, in the midst of a bunch of subversion client updates, some client decided that I was working with ASP.Net files.  So, the "SVN_ASP_DOT_NET_HACK" environment variable got set.  This causes subversion's directories to be named "_svn" rather than ".svn."  This would be great if I needed the feature to prevent ASP.Net from getting confused.  However, it turned out to be a royal pain in the rear, and a big confusion for Eclipse.  Eclipse does NOT ignore "_svn" files correctly.&lt;br /&gt;&lt;br /&gt;It was quite a shock to suddenly see a bunch of _svn folders on one machine, but not another when working with the same repository.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-4762192790392735635?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/4762192790392735635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=4762192790392735635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4762192790392735635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/4762192790392735635'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2008/01/when-subversion-goes-crazy.html' title='When Subversion Goes Crazy'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8994368557119750169</id><published>2007-11-02T20:29:00.000-07:00</published><updated>2007-11-03T23:45:22.449-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnetconf'/><title type='text'>Alt.Net Mailing List - The Hidden Benefits</title><content type='html'>Since the Alt.Net &lt;a href="http://tech.groups.yahoo.com/group/altnetconf/"&gt;mailing list&lt;/a&gt; saw it's first post on October 8, 2007, the list has seen an average of 87 posts per day.  The content is wonderful (now that we aren't arguing about the name so much).&lt;br /&gt;This high volume has also done wonders for my ability to scan and speed read.  This is a skill that I had during my schooling but seemed to have lost.  Now that I have been following this mailing list, I have seen much more zero-bounce in my blog reader - even though I have more feeds coming in.&lt;br /&gt;&lt;br /&gt;Now, I can finally keep up with the volume of content coming from &lt;a href="http://www.ayende.com/Blog/"&gt;Ayende's blog&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8994368557119750169?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8994368557119750169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8994368557119750169' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8994368557119750169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8994368557119750169'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/11/altnet-mailing-list-hidden-benefits.html' title='Alt.Net Mailing List - The Hidden Benefits'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-9143742855256406545</id><published>2007-10-31T09:17:00.000-07:00</published><updated>2007-10-31T09:48:16.444-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='team'/><title type='text'>Am I Doing Scrum? - Nokia's Benchmark for Scrum Adoption</title><content type='html'>Dr. Jeff Sutherland, and Agile Manifesto signatory,  has posted an excellent interview, &lt;a href="http://www.infoq.com/interviews/jeff-sutherland-scrum-rules"&gt;"Scrum and Not-Scrum"&lt;/a&gt;.   As part of this interview, he advocates eight questions that Nokia uses to determine if their teams have adopted Scrum.  Jeff presents this as a boolean test.  If the team can answer "yes" to all eight of these questions, they are doing Scrum.  If any question gets a "no," then they have not fully adopted Scrum.  Here are the questions:&lt;br /&gt;&lt;br /&gt;First Tier:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Are you doing &lt;span style="font-weight: bold;"&gt;iterative development&lt;/span&gt;?&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Do you have a &lt;span style="font-weight: bold;"&gt;fixed&lt;/span&gt; iterations lasting less than six weeks?&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;At the end of the iteration, do you have &lt;span style="font-weight: bold;"&gt;working software&lt;/span&gt;?&lt;/li&gt;&lt;li&gt;Can the team effectively start work on an iteration &lt;span style="font-weight: bold;"&gt;without a detailed specification&lt;/span&gt;?&lt;/li&gt;&lt;li&gt;Is &lt;span style="font-weight: bold;"&gt;testing&lt;/span&gt; part of the increment?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Second Tier:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Do you have a &lt;span style="font-weight: bold;"&gt;product owner&lt;/span&gt;?&lt;/li&gt;&lt;li&gt;Does the product owner have a prioritized, estimated product &lt;span style="font-weight: bold;"&gt;backlog&lt;/span&gt;?&lt;/li&gt;&lt;li&gt;When the team is developing, do they have a &lt;span style="font-weight: bold;"&gt;burndown chart&lt;/span&gt;?&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Can you calculate the team's velocity?&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Is the team &lt;span style="font-weight: bold;"&gt;self-organizing&lt;/span&gt;?&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;In other words, does the team choose, assign, and map the fastest possible way to deliver the work?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The project manager cannot interfere with the team during an iteration.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;I highly recommend watching this interview.  It is only about 20 minutes long, and it is packed with good information including a summary of Google's &lt;a href="http://en.wikipedia.org/wiki/Boiling_frog"&gt;boiled frog&lt;/a&gt; adoption of Scrum on the AdWords project.&lt;br /&gt;&lt;br /&gt;Jeff also reminds us that Scrum will not solve your organizational problems, but it will make them painfully obvious.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-9143742855256406545?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/9143742855256406545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=9143742855256406545' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/9143742855256406545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/9143742855256406545'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/am-i-doing-scrum-nokias-benchmark-for.html' title='Am I Doing Scrum? - Nokia&apos;s Benchmark for Scrum Adoption'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-5609869541148607521</id><published>2007-10-30T06:42:00.001-07:00</published><updated>2007-10-31T10:19:59.089-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='integration testing'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Programmers Anonymous:  Confessions of a Terrible Software Developer</title><content type='html'>Marc has posted his "&lt;a href="http://kickin-the-darkness.blogspot.com/2007/09/confessions-of-terrible-programmer.html"&gt;Confessions of a Terrible Programmer.&lt;/a&gt;"  The overriding tone of the post can be summed up in the following pseudo-Zen quotes:&lt;br /&gt;&lt;div style="margin: 0px 20px; font-style: italic;"&gt;&lt;br /&gt;You will never become a Great Programmer until you acknowledge that you will always be a Terrible Programmer.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;and,&lt;br /&gt;&lt;div style="margin: 0px 20px; font-style: italic;"&gt;&lt;br /&gt;You will remain a Great Programmer for only as long as you acknowledge that you are still a Terrible Programmer.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Marc does a very good job of stating how he overcomes his "terribleness" to provide working software.  According to Marc, his solutions are doing a good job of hiding the fact that he is a terrible developer.  However, I believe that agile practices present different solutions to these problems.  In broad terms, Marc favors failing fast where I favor multiple levels of testing, Test-Driven Design, and the fast feedback loops provided by good test coverage coupled with Continuous Integration.&lt;br /&gt;&lt;br /&gt;To address more specifics, I have provided a summary of Marc's solutions along with where I think agile solves these in a different way.&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Marc says he favors strong typing to prevent problems.  Having done most of my work in static languages (Java, C#), and some in dynamic language (Groovy), at this point I prefer solid unit test coverage (100% with excuses).  Test-first design helps with this too.  Once I have good test coverage, those tests are unearthing the same problems that the compiler would.  With the dynamic languages, I find the same errors a bit later, but I get the benefit of code that I find to be much easier to read.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Marc favors programming assertions.  Marc is a paranoid programmer.  He will assert that something is not null even when he controls both sides of the interface - just in case he might change something later.  I personally find that assertions and paranoid programming in general fall under the related headings of YAGNI and nosiy code.  Instead, I prefer solid unit testing and a tester that knows how to unearth the edge cases.  Write unit tests that assert that the service in question does not return null to box in the behavior.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Marc says he will, "ruthlessly try to break [his] own code."  It appears that Marc is trying to accomplish through developer testing what should be done by an actual tester.  While I agree that developers should be generating tests that give great code coverage, it is a waste of time to make them switch hats and become a tester for their own code.  Hire a tester.  They think differently from developers.  Their concerns are different.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Marc favors code reviews.  I favor pair programming.  Both provide feedback, but I want my feedback while I'm "in the zone."  I want my feedback immediately.  I don't want you to sit back and wait for me to find my own bugs.  If you see something, tell me.  Tell me as soon as it looks like I've finished typing or as soon as it looks like I'm looking for the bug.  This way, I can fix the problem without having to make the context switch to come back to it later.  Plus, the quality of the review is better since the other developer should be equally engaged in the generation of the code while it is being generated.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;To be honest, our team is not able to follow all of these guidelines at the moment.  Our biggest problem is not having a dedicated software tester embedded with the team.  We ARE having to generate the types of tests that a dedicated tester should be doing.  And, we are missing some things that a tester would catch much earlier in the development process.  I feel that this missing component of our team IS hurting our velocity.&lt;br /&gt;&lt;br /&gt;Am I a terrible programmer?  Yes.  If you find me stating otherwise, please redirect me to some of my own code - something that I wrote yesterday should do just fine.&lt;br /&gt;&lt;br /&gt;What are you doing to hide the fact that you're a terrible developer?  I would love to hear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-5609869541148607521?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/5609869541148607521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=5609869541148607521' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5609869541148607521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5609869541148607521'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/programmers-anonymous-confessions-of.html' title='Programmers Anonymous:  Confessions of a Terrible Software Developer'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-3055695413723115697</id><published>2007-10-26T06:54:00.000-07:00</published><updated>2008-01-13T19:11:01.670-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>How To Pass Command Arguments With a File Type</title><content type='html'>&lt;span style="font-weight: bold;"&gt;UPDATE:  This issue appears to be fixed with the Groovy 1.5 Windows install package.  However, this is still good general information to know about passing command arguments with file associations in Windows.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I just upgraded my groovy install to the latest RC for 1.1, and it quit recognizing command arguments.  I tried debugging all kinds of older scripts that I knew worked, and none of them were working anymore.  That's when Steve reminded me that the Groovy install messes up the Windows file extension association.  So, it installed the .groovy file association like this:&lt;br /&gt;&lt;br /&gt;"C:\groovy\bin\groovy.exe" "%1"&lt;br /&gt;&lt;br /&gt;And it needed to be changed to this:&lt;br /&gt;&lt;br /&gt;"C:\groovy\bin\groovy.exe" "%1" %*&lt;br /&gt;&lt;br /&gt;This will allow the other command arguments to be passed when the groovy script is kicked off.&lt;br /&gt;&lt;br /&gt;To change the file association (in XP),&lt;br /&gt;&lt;br /&gt;* Open My Computer&lt;br /&gt;* Tools -&gt; Folder Options...&lt;br /&gt;* Click the "File Types" tab&lt;br /&gt;* Find the file type you want to change, ".groovy" in this case, and click it&lt;br /&gt;* Click the "Advanced" button&lt;br /&gt;* Click the "open" action&lt;br /&gt;* Click the "Edit..." button&lt;br /&gt;* Edit the content of the text box under, "Application used to perform action:"&lt;br /&gt;* OK / Close your way out of the dialogs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Obviously, this will work for other file associations.  This method, while it forces you through a few windows, allows you to avoid mucking with the registry directly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-3055695413723115697?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/3055695413723115697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=3055695413723115697' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3055695413723115697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3055695413723115697'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/how-to-pass-command-arguments-with-file.html' title='How To Pass Command Arguments With a File Type'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-9041215033695866514</id><published>2007-10-22T15:05:00.000-07:00</published><updated>2007-10-22T15:18:43.380-07:00</updated><title type='text'>Don't Get Fooled</title><content type='html'>Junk is junk.  Whether it comes in your (snail) mailbox or your Inbox, it's junk. &lt;br /&gt;&lt;br /&gt;Scott has a post asking how to teach common sense when  &lt;a href="http://feeds.feedburner.com/%7Er/ScottHanselman/%7E3/172768056/WebCommonSenseIsntTooCommon.aspx"&gt;here&lt;/a&gt;.  Some will learn, some won't.&lt;br /&gt;&lt;br /&gt;People that fall for scams fall for them whether they come by snail mail, telephone, or email  Email is the easiest to perpetrate.  Therefore, more people are falling for email scams these days.&lt;br /&gt;&lt;br /&gt;The unfortunate thing is that I haven't found a way to foist pain back onto those that are populating my Inbox with crap.  Actually, my filters are pretty good these days, so I don't see most of it.&lt;br /&gt;&lt;br /&gt;With telephone scams, my game is (when I have the spare time) to keep them on the phone for as long as possible.  I once kept a scammer on the phone for two hours while he kept trying different ways to get me to tell him my bank account and routing number.  At least for those two hours, I knew that THAT guy was not scamming someone's grandmother.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-9041215033695866514?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/9041215033695866514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=9041215033695866514' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/9041215033695866514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/9041215033695866514'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/dont-get-fooled.html' title='Don&apos;t Get Fooled'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-1566193978356754487</id><published>2007-10-10T05:56:00.000-07:00</published><updated>2007-10-10T08:09:43.265-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='team'/><title type='text'>Why Are You Asking Me This Question?</title><content type='html'>Any developer that's been around this industry for any length of time has found himself in a conversation like this one:&lt;br /&gt;&lt;br /&gt;Manager:  Hey, Mr. Developer, TheBusiness has decided that we need to develop a product to do XYZ.  How long will that take?&lt;br /&gt;Developer:  Hrm... I'm not sure.  What are the details of XYZ?&lt;br /&gt;Mgr:  The details aren't important.  I just need an estimate&lt;br /&gt;Dev:  Well... something like 8 weeks.&lt;br /&gt;Mgr:  Okay, well how much longer until you finish the thing you're working on?&lt;br /&gt;Dev:  Around 4 weeks&lt;br /&gt;Mgr:  Okay.  Thanks.&lt;br /&gt;&lt;br /&gt;[10 weeks later]&lt;br /&gt;&lt;br /&gt;Mgr:  So, Dev, I'm looking forward to having this XYZ product.  We've already sold it to 50 customers and they're excited to be getting it in two weeks.&lt;br /&gt;Dev:  WHAT?!?!?!&lt;br /&gt;&lt;br /&gt;This is not a fun series of conversations.  The breakdowns in communication should be obvious.  The manager (unknowingly) expected way too much precision from the developer's estimate, and the developer gave it without nearly enough qualifying statements pointing out that it's a &lt;a href="http://www.google.com/search?q=wild+ass+guess"&gt;WAG&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, how can this be fixed?  Many developers that I know say, just don't provide the estimate.  While most of us could get away with that, it doesn't necessarily help the conversation.  I prefer to answer with, "Why are you asking me this question?"  This is a question that I learned to ask by watching a former team lead, Glenn Burnside.  Whenever a salesperson or manager would ask the team a question like, "How difficult would it be to...," Glenn's response was always the same - he would ask this question.  This always resulted in a conversation that fleshed out a more detailed question (or questions) and much better, more precise answers.&lt;br /&gt;&lt;br /&gt;The hardest part of software development is interacting with those objects that have a pulse - not those that have a system clock.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-1566193978356754487?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/1566193978356754487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=1566193978356754487' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/1566193978356754487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/1566193978356754487'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/why-are-you-asking-me-this-question.html' title='Why Are You Asking Me This Question?'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-2698267852037833783</id><published>2007-10-07T21:16:00.000-07:00</published><updated>2007-10-07T21:42:47.480-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnetconf'/><title type='text'>altnetconf - Cool Tools Don't Make Cool Software</title><content type='html'>I'm pretty sure that Jimmy Hendrix could make awesome music with a cheap guitar.  Likewise, I could drop $5000 on a beautiful vintage guitar and I still won't be going on tour with anyone.  The artist makes the tool work.  While good tools make the artist's life a bit easier, they don't make the artist.&lt;br /&gt;&lt;br /&gt;Likewise, it is perfectly possible to write clear, maintainable software without the use of things like &lt;a href="http://martinfowler.com/articles/injection.html"&gt;inversion-of-control&lt;/a&gt; containers and mock frameworks.  This weekend at the Alt.Net conference, I spoke with some very smart developers that don't use these tools that I take for granted.  Tools that I even view as a necessary item.  One developer that I spoke with stated that he has yet to find a need to use a mocking framework.  Instead, he prefers the Testable Object pattern.  I was completely taken aback until I grokked what his explanation.  While I'm not going to drop my use of easymock, I see that this is certainly a valid way to do things.&lt;br /&gt;&lt;br /&gt;I had the opportunity to speak with another developer this weekend - a brilliant developer and the second person ever added to my feed list.  When the table at lunch started talking about IoC containers, he said that he's never seen the need for one.    I found this to be very surprising.  Once a couple of us explained why we like and use tools like StructureMap and Guice, he quickly grokked what was going on, and I think he could see why some find them to be useful tools to have.  However, it also became clear that he had found other ways around the pain of supplying dependencies when using Dependency Injection.&lt;br /&gt;&lt;br /&gt;All of this is to say that I was reminded that I don't have to pull in every tool under the sun.  It's good to keep my head up and take a look at what others are doing to alleviate problems.  However, there are also other ways around problems that may not involve pulling in yet one more tool.&lt;br /&gt;&lt;br /&gt;It's not the tools that make the software good.  It's the developers that apply sound judgement and experience - regardless of what tools they have.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-2698267852037833783?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/2698267852037833783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=2698267852037833783' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2698267852037833783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/2698267852037833783'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/altnetconf-cool-tools-dont-make-cool.html' title='altnetconf - Cool Tools Don&apos;t Make Cool Software'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8929495150946138012</id><published>2007-10-06T12:32:00.000-07:00</published><updated>2007-10-06T12:41:24.543-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnetconf'/><title type='text'>altnetconf - Random Thoughts on Fishbowl</title><content type='html'>Some of the sessions are using the &lt;a href="http://www.anecdote.com.au/archives/2006/12/the_open_space.html"&gt;fishbowl&lt;/a&gt; format.  This is a really fun format that lets just about anyone that wants it the opportunity to contribute content to the conversation.  However, this did not work very well during the BDD Discussion most likely because code samples were being periodically presented on the projector.  This was proof positive that if your turn on a video source, the entire audience will focus on it.  In this case, chairs were setup for the fishbowl, but the fishbowl rules were not followed by the audience.  Because the group was focused on the screen rather than the chairs and the people in them, the conversation was not controlled.&lt;br /&gt;&lt;br /&gt;Either present video or do the fishbowl, but it seems you cannot do both at the same time&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8929495150946138012?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8929495150946138012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8929495150946138012' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8929495150946138012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8929495150946138012'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/altnetconf-random-thoughts-on-fishbowl.html' title='altnetconf - Random Thoughts on Fishbowl'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-5103847896508936109</id><published>2007-10-06T09:28:00.000-07:00</published><updated>2007-10-06T14:25:08.540-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnetconf'/><category scheme='http://www.blogger.com/atom/ns#' term='Behavior Driven Design (BDD)'/><title type='text'>altnetconf - Behavior Driven Design</title><content type='html'>This post is separated into summary and thoughts.&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;This thing called "Behavior Driven Design" (BDD) doesn't seem to have a formalized definition.  Not everyone in attendance could agree on what "it" is.  However, the most clear definition presented involves several components.  &lt;a href="http://codebetter.com/blogs/scott.bellware/"&gt;Scott Bellware&lt;/a&gt; asserted that BDD = &lt;a href="http://www.extremeprogramming.org/rules/userstories.html"&gt;UserStories&lt;/a&gt; + &lt;a href="http://www.agiledata.org/essays/tdd.html"&gt;TDD&lt;/a&gt; + &lt;a href="http://domaindrivendesign.org/discussion/messageboardarchive/UbiquitousLanguage.html"&gt;UbiquitousLanguage&lt;/a&gt; + &lt;a href="http://javascript.codebetter.com/blogs/scott.bellware/archive/2007/04/07/161406.aspx"&gt;Solubility&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Some constraints on the above components should be explained.  User stories must be well-formed.  So, the idea is that during a conversation that the business analyst and the developer would work together to produce a story of the form "As a... I want to... So that..."  The assumption is made that the TDD being used is driving design at a granular level with only one assertion per test.  To extend Scott's definition of Solubility linked to above, another term "grokability" was proposed by Scott &lt;a href="http://www.hanselman.com/blog/"&gt;Hanselman&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The Behavior Driven Design (BDD) session began with many questions, asked many more, and perhaps answered a few things.  Bellware started by saying that BDD is not about testing.  He later stated that BDD provides better tests.  So, to summarize, BDD is not about testing... except when it is.  So, that make that about as clear as mud.&lt;br /&gt;&lt;br /&gt;Much of the discussion centered on improving the conversation.  More specifically, the conversation between the developer and the business analyst was discussed.&lt;br /&gt;&lt;br /&gt;One criticism presented is that BDD is using programming languages to discuss things with the business analyst.  The concern was that we would be asking business analysts to write specifications including the markup.  This bred a great deal of consternation.&lt;br /&gt;&lt;br /&gt;This critique was perhaps diffused later when the suggestion was made that the business analyst would sit down with the programmer, and the two would discuss the user story and the specifications.  During that discussion, the developer would transcribe the conversation into the story markup used by the spec tool (RSpec, NBehave...).  Another possibility presented was that the conversation could be initially captured onto a story card and then transcribed to the tool by the developer at a later time.&lt;br /&gt;&lt;br /&gt;There was the assertion made that BDD provides or formalizes context for conversations with the business analyst and context for the developer to write the implementation.&lt;br /&gt;&lt;br /&gt;Scott Hanselman says, "This is like NUnit that generates prose."  There seems to be a bit of buy-in for this.  Perhaps C# doesn't lend itself to the readability of the spec implementation.  The business owner writes this through the ears of the developer that is sitting next to him.&lt;br /&gt;&lt;br /&gt;Part of BDD is generating a specification document directly from the tests.  This allows the tests and the information being passed back to the business analyst to stay in sync better.  This is NOT to replace verbal communication, but again to provide a talking point to augment the conversation.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Thoughts&lt;/h3&gt;&lt;br /&gt;It seemed as though the thoughts around BDD have application in many parts of the development life-cycle.  BDD practices are useful for clarifying the discussions that should be taking place during the entire process.  The initial definition of user stories is helped by these practices.  During development, BDD practices help developers see the bigger picture.  Finally, and importantly, the executable specifications serve as a note to the future self.  In other words, when you come back to the code, it is easier to understand why the test was written in the first place.&lt;br /&gt;&lt;br /&gt;Much of the confusion came about because these thoughts are useful in so many different places.  It seemed that participants saw the potential to have certain pains alleviated, then latched onto that particular portion of usefulness.  BDD is aspect-oriented.  It is a cross-cutting concern and does not simply fit into a single portion of the development process.  Wherever there is conversation in the development process, formalizing that conversation helps to remove ambiguity.&lt;br /&gt;&lt;br /&gt;Perhaps this is more useful when you MUST generate documentation.  Not everyone needs to have everything generated in paper form.  For some business, people, they feel better seeing the specifications generated as either a sheet of paper or a web site.  Even in situations where this documentation must be generated, this documentation is not set in stone.&lt;br /&gt;&lt;br /&gt;I'm pretty convinced that we don't need a separate tool to do effective Behavior Driven Design.  We need to get much better at language - both natural language and expressing natural language with programming languages.  As if the natural language wasn't ambiguous enough, we are forced to complicate it by writing something that the  parser can understand.&lt;br /&gt;&lt;br /&gt;The conversation about this is still in process.  I'm sure that I don't know everything about this.  I hope to continue to look in this area and find ways to write better software with less pain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-5103847896508936109?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/5103847896508936109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=5103847896508936109' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5103847896508936109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5103847896508936109'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/altnetconf-behavior-driven-design.html' title='altnetconf - Behavior Driven Design'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-13045121231455073</id><published>2007-10-05T22:18:00.000-07:00</published><updated>2007-10-06T05:31:24.306-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnetconf'/><title type='text'>altnetconf - Alt.Net First Impressions</title><content type='html'>I'm not sure how much I will find myself around the computer this weekend, but I thought I would post my impressions of the &lt;a href="http://www.altnetconf.com"&gt;ALT.Net &lt;/a&gt;conference as we go along.  The comments during the opening remarks and fishbowl seemed to center around a few core concepts:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Though perceptions might be otherwise, nobody expressed total contempt or hatred of Microsoft.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Everyone wants to write better software.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Writing better software probably means using tools that weren't developed in Redmond.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The overriding of "better software" seems to be maintainability.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Drag-and-drop is still the whipping boy of this crowd.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Alt.Net IS alternative because most .Net developers seem to use whatever tools Microsoft puts out (and MSDN talks about).  Conference attendees are much more likely to use tools that are alternatives to simply the set put out by Microsoft.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I'm looking forward to hearing more opinions and thoughts as we go along.  I'm not sure how much will be decided.  Many seem to want to come to a consensus, but everyone in attendance is so passionate that it may not happen.  We'll see.  At least we're trying to figure out what is going on and how we can deliver better software for all involved.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-13045121231455073?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/13045121231455073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=13045121231455073' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/13045121231455073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/13045121231455073'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/altnet-first-impressions.html' title='altnetconf - Alt.Net First Impressions'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-6037109257656095471</id><published>2007-10-03T08:59:00.000-07:00</published><updated>2007-11-03T23:43:27.710-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Don't Use Mocks...</title><content type='html'>...when you aren't really interested in testing the interactions.  This is related to my &lt;a href="http://testinfected.blogspot.com/2007/09/write-better-tests-using-combination-of.html"&gt;previous post&lt;/a&gt; regarding mocks and stubs.  If leaving off the verification of mocks wouldn't change the nature of what you are testing, then you aren't writing an interaction-based test.  Therefore, the mock dependency probably creates more noise than simply using a simple stub.  If your dependency is not behind an interface, you can in most cases still create a stub using &lt;a href="http://grabbagoft.blogspot.com/2007/08/legacy-code-testing-techniques-subclass.html"&gt;subclass and override&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;While writing:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Dependency dependency = createMock(Dependency.class);&lt;br /&gt;expect((Foo)dependency.bar(anyObject())).andReturn(somethingValid);&lt;br /&gt;ThingToTest target = new ThingToTest(dependency);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;isn't too bad.  It still causes more noise than:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ThingToTest target = new ThingToTest(new DependencyStub());&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Most of the time, I see that stub and grok the fact that in the context of this test, I really don't care what the Class under test does with that dependency.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-6037109257656095471?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/6037109257656095471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=6037109257656095471' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6037109257656095471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/6037109257656095471'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/10/dont-use-easymock.html' title='Don&apos;t Use Mocks...'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-8611722873244395777</id><published>2007-09-29T19:19:00.000-07:00</published><updated>2007-11-03T23:43:53.629-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Write better tests using a combination of mocks and stubs.</title><content type='html'>&lt;span style="font-family:verdana;"&gt;I love using &lt;a href="http://www.easymock.org/"&gt;EasyMock.&lt;/a&gt;  It's just plain, well, easy to use most of the time.  Most of the time, it doesn't get in my way.  However, there are certain times when I will avoid using a mock object in a test.  This is best show by example.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;As background, remember that mocks are not stubs and stubs are not mocks.  You can use a mocking framework (like easymock) to create stubs, and you can even create mocks by hand (with a good deal of pain).  Roy Osherove has done a great job of describing the differences between mocks and stubs.  You should &lt;a href="http://feeds.feedburner.com/%7Er/Iserializable/%7E3/157332221/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx"&gt;check out Roy's explanation.&lt;/a&gt;  This is a different explanation from what I've seen before.  If you want a good, detailed description of the differences, Martin Fowler has provided an in-depth comparison between the two including code samples.  You should &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;take a look at&lt;/a&gt; Fowler's explanation to understand the terminology.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;I won't rehash the explanations.  What I will say is that I've found value in doing both interaction-based testing (with mocks) and state-based testing (with stubs).  When your classes are well decomposed and decoupled, mock testing makes more sense in most cases.  However, when I'm interested in how a particular piece of code affects state on objects that pass through it, I will use a stub.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Here's the promised example.  Supposed a I have a class, we'll call Processor that interacts with a dependency that sits behind and interface called EmailService.  I'm interested in testing that Processor.emailManagers("we have a problem") can create an instance of Email with the correct properties set and hand that off to the EmailService.  Looking at the test first, we have:&lt;/span&gt;&lt;br /&gt;&lt;samp&gt;&lt;br /&gt;&lt;span&gt;@Test&lt;/span&gt;&lt;br /&gt;&lt;span&gt;public void myTest() {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  EmailServiceStub serviceStub = new EmailServiceStub();&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  Processor processor = new Processor(serviceStub);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  processor.emailManagers("This should be working");&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  email = serviceStub.getLastSentEmail();&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  assertNotNull(email);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  assertEquals("This should be working", email.getMessage());&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  assertEquals("managers@FooInc.com", email.getTo());&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  assertEquals("An Automated Message from 'The System'", email.getSubject());&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  assertEquals("TheSystem@FooInc.com", email.getFrom());&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/samp&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Obviously, we'll need something to stand in the place of the EmailService so that we don't actually send an email in the course of running this unit test.  The stand-in for this test is done by a stub like this:&lt;/span&gt;&lt;br /&gt;&lt;samp&gt;&lt;br /&gt;&lt;span&gt;public class EmailServiceStub implements EmailService {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  Email lastSentEmail = null;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  public void send(Email email) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    this.lastSentEmail = email;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  public Email getLastSentEmail() { return this.lastSentEmail; }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/samp&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;The actual implementation code for Processor then might look like this:&lt;/span&gt;&lt;br /&gt;&lt;samp&gt;&lt;br /&gt;&lt;span&gt;public class Processor {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  EmailService emailService;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  public Processor (EmailService emailService) { this.emailService = emailService}&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  public emailManagers(String message) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    Email email = new Email();&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    email.setBody(message);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    email.setSubject("An Automated Message from 'The System'");&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    email.setTo("managers@FooInc.com");&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    email.setFrom("TheSystem@FooInc.com");&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    emailService.send(email);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/samp&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;To be fair, this kind of testing is possible with EasyMock as well.  You CAN check the properties of the object that are passed to send() using EasyMock.  However, I find it incredibly painful to do so.  What's worse, it makes the test convoluted to read.  EasyMock would have you define your own implementation of IArgumentMatcher as indicated &lt;a href="http://www.easymock.org/EasyMock2_0_Documentation.html"&gt;here&lt;/a&gt;.  (search for "Defining own Argument Matchers").  Blech!  We've done this before, and it seems to make the tests much more difficult to grok when I come back to them.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;There are plenty of good examples of when you would want to use mocks over stubs.  The Fowler post linked to at the top is a good start.  I still use mocks for most of my testing, but in this instance, it's easier to use a stub than battle EasyMock.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-8611722873244395777?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/8611722873244395777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=8611722873244395777' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8611722873244395777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/8611722873244395777'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/09/write-better-tests-using-combination-of.html' title='Write better tests using a combination of mocks and stubs.'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-3195200803209209804</id><published>2007-09-26T08:48:00.000-07:00</published><updated>2008-05-31T13:45:18.616-07:00</updated><title type='text'>Convention Over Configuration is Nice... Except When It Isn't</title><content type='html'>Convention over configuration should lead to predictability.  This breaks down when the default behavior of a system is unexpected.  Take &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice&lt;/a&gt; for example.  Guice will automatically bind to a class if the only constructor is a zero-argument constructor.  This will happen even if the constructor is private.&lt;br /&gt;&lt;br /&gt;This is not the path of least surprise when I forget to configure the behavior.  I don't mind there being default behavior, I would just like to be able to turn it off.  Moreover, I would like the opportunity to turn certain features off.&lt;br /&gt;&lt;br /&gt;Private should mean private at least.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-3195200803209209804?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/3195200803209209804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=3195200803209209804' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3195200803209209804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3195200803209209804'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/09/convention-over-configuration-is-nice.html' title='Convention Over Configuration is Nice... Except When It Isn&apos;t'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-3143989253396667425</id><published>2007-09-11T06:23:00.000-07:00</published><updated>2007-11-03T23:44:40.879-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FIT testing'/><category scheme='http://www.blogger.com/atom/ns#' term='integration testing'/><title type='text'>Warning:  Frustrating Toolsets Ahead</title><content type='html'>The opinions expressed here are in the context of working on relatively short-term projects against a legacy code base.  If this is not your situation, adjust or ignore as appropriate.&lt;br /&gt;&lt;br /&gt;I love tools.  I'm a huge believer in using the right tool for the job.  Perhaps this is because I can use that crutch as a good excuse to hit the local big orange box when I start a new project.  Regardless, I've found that tools that some have labeled "frustrating" have been downright helpful and productive in our projects.&lt;br /&gt;&lt;br /&gt;Last week, Scott pointed out that perhaps &lt;a href="http://codebetter.com/blogs/scott.bellware/archive/2007/09/05/167500.aspx"&gt;user stories don't make good test artifacts&lt;/a&gt;.  I'm inclined to agree.  Jeremy has also reminded us in the value of testing small before testing big &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/09/07/i-still-think-bdd-needs-a-bit-of-v-model-thinking.aspx"&gt;here&lt;/a&gt;.  While I see the value of this, I don't agree that the small (unit) tests all need to be written before the larger (integration) tests.&lt;br /&gt;&lt;br /&gt;To provide a bit of background, my team largely works on writing Java applications that import data from a variety of sources into the existing system at &lt;a href="http://www.drillinginfo.com/"&gt;DrillingInfo&lt;/a&gt;.  To be clear, we don't work much with the web front-end.  Our main job is bringing new data sources on-line and making the data make sense within our existing domain model.  Therefore, the internal customers are only tangentially concerned with the appearance of our final product.  They are really more concerned that data makes it into the system in a way that fits the existing system.  They might even express their desires in terms of how new data should appear on the web site.  Those requirements are then (roughly) translated into story cards and the story cards are reviewed by the team and the customer.&lt;br /&gt;&lt;br /&gt;With that background, I say that the story cards take a relatively minor role in driving day-to-day development.  At the start of any iteration, the story cards are used to spin out tasks.  Some of the tasks are features (the process should convert incoming data with a value of 'x' to the value of 'y'), or they could be technical (setup the demo server).  Then, the team estimates complexity for the individual tasks.  During an iteration, we look at the task cards -- not the story cards.&lt;br /&gt;&lt;br /&gt;On a day-to-day basis, we tend to use &lt;a href="http://fitnesse.org/"&gt;Fitnesse&lt;/a&gt; to provide direction for the unit tests that need to be written.  Our goal when looking at a new feature is to have a pair sit down and sketch out a Fitnesse test.  Once that has been done, we'll sit down with the customer and make sure that the behavior outlined in the Fitnesse is what they expect.  Then, we right the fixture code to clear all of the Method Not Found exceptions that the Fitnesse test initially causes.  At this point we have a nice, red, failing test for a feature.&lt;br /&gt;&lt;br /&gt;After getting the large test in place (and failing), we start looking at where the system needs to be extended, perhaps do a little whiteboarding, and start writing unit tests.  The failing Fitnesse test helps keep us on target.  Quite often, one of the developers in the pair will have to say, "now, what Fit test are we trying to make pass?"  Just like with unit testing, we sometimes find other behaviors that need to be specified.  Usually one half of the pair will pull off and capture enough information on a task card so that we don't forget it.&lt;br /&gt;&lt;br /&gt;The shortcomings of Fitnesse have been well articulated (&lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/08/12/why-i-m-suddenly-down-on-fit-fitnesse.aspx"&gt;here&lt;/a&gt; and &lt;a href="http://www.mattberther.com/?p=813"&gt;here&lt;/a&gt; and &lt;a href="http://codebetter.com/blogs/scott.bellware/archive/2006/09/09/149105.aspx"&gt;here&lt;/a&gt;).  I'll say that the one I find to be most frustrating is lack of refactoring support.  When I change the wording in my tests, I have to go change method names.  But, since our projects are relatively small (1 -  2 months), we don't end up with so many Fitnesse tests that this is a large problem.&lt;br /&gt;&lt;br /&gt;Because we use the Fitnesse tests to drive discussions with our customers, nobody has ever come back and said, "well, the tests that you've got in place are great, but the system isn't really doing what I want."  While looking at Fitnesse, the customer does not forget what they wanted, and they often remember things they forgot to ask for initially.  The story cards are not useless, they just don't get used much once the team gets going.&lt;br /&gt;&lt;br /&gt;All in all, I'd say that we hit a pretty good flow of writing Fit tests, having conversations, writing unit tests, and making everything green.  It's certainly possible that on a longer-term project with more features, we would find ourselves frustrated by the tools that we currently find to be productive.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-3143989253396667425?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/3143989253396667425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=3143989253396667425' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3143989253396667425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/3143989253396667425'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/09/warning-frustrating-toolsets-ahead.html' title='Warning:  Frustrating Toolsets Ahead'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-7668038690722762260</id><published>2007-08-13T23:50:00.000-07:00</published><updated>2007-10-05T23:25:05.108-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Using Groovy to grep XML</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;After attending some compelling presentations by &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.nofluffjuststuff.com/speaker_view.jsp?speakerId=18"&gt;Scott Davis&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; at &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.nofluffjuststuff.com/"&gt;No Fluff Just Stuff,&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; I have been playing with &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; here and there when I've gotten the chance.  At work, we've been working with a some software that's currently producing a pretty massive log file.  We tried using Chainsaw to slice and dice it, but it wasn't giving us the functionality that we wanted.  So, this was a perfect time to play with some Groovy.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Our input looks something like this:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div  style="font-family:courier new;"&gt;&lt;span style="margin-left: 0em;"&gt;&amp;lt;root&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;entry level="ERROR"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="margin-left: 3em;"&gt;An error has occurred while parsing column FOO with value of BAR 23 in row 234&lt;/div&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;/message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;entry level="ERROR"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="margin-left: 3em;"&gt;An error has occurred while parsing column FOO with value of BAR 52 in row 234&lt;/div&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;/message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;entry level="ERROR"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="margin-left: 3em;"&gt;An error has occurred while parsing column FOO with value of FOOBAR 34 in row 234&lt;/div&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;/message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;entry level="ERROR"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="margin-left: 3em;"&gt;An error has occurred while parsing column FOO with value of FOO52 in row 234&lt;/div&gt;&lt;span style="margin-left: 2em;"&gt;&amp;lt;/message&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 1em;"&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="margin-left: 0em;"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Of course, the file is too massive to read through.  For this particular error, we were interested in the unique values of FOO that we weren't handling.  Here is the groovy to pop open the XML file and find the unique values&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;samp&gt;&lt;br /&gt;&lt;span&gt;def findUniqueEntries(String inputPath, String search, String extract) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    def uniqueMatches = new HashMap()&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span&gt;    //Input all of the XML&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    def root = new XmlParser().parse(new File(inputPath))&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    //All the child nodes of the root node will be &lt;entry&gt; elements&lt;/entry&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    for (entry in root.children()) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;        &lt;/span&gt;&lt;br /&gt;&lt;span&gt;        //Assumes each &lt;entry&gt; has exactly one &lt;message&gt; child&lt;/message&gt;&lt;/entry&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;        text = entry.message[0].text()&lt;/span&gt;&lt;br /&gt;&lt;span&gt;        &lt;/span&gt;&lt;br /&gt;&lt;span&gt;        //Do a substring search first&lt;/span&gt;&lt;br /&gt;&lt;span&gt;        if (text.contains(search)) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            &lt;/span&gt;&lt;br /&gt;&lt;span&gt;            //Strip out the failing value with a Regular Expression&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            def matcher = text =~ extract&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            uniqueValue = matcher[0][1]&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            &lt;/span&gt;&lt;br /&gt;&lt;span&gt;            //For values we've seen before, increment the count&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            if (uniqueMatches[uniqueValue] != null) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;                uniqueMatches[uniqueValue] += 1&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            &lt;/span&gt;&lt;br /&gt;&lt;span&gt;            //For a new value, initialize the count&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            else {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;                uniqueMatches[uniqueValue] = 1&lt;/span&gt;&lt;br /&gt;&lt;span&gt;            }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    //Print the values along with their occurance count&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    for (match in uniqueMatches) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;        println match&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span&gt;    //Print the number of unique matches, and the number of total matches.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    def uniqueMatchCount = uniqueMatches.size()&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    def totalMatchCount = uniqueMatches.values().sum()&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    println ('\nFound ' + uniqueMatchCount + ' unique matches in ' &lt;/span&gt;&lt;br /&gt;&lt;span&gt;        + totalMatchCount + ' total matches.\n')&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/samp&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;There are a couple of interesting things that made this really fun code to write:&lt;br /&gt;&lt;br /&gt;1 - Navigating XML with Groovy is easy, and the syntax reads quite well.  The code communicates the structure of the XML document as well as could be expected, I think.&lt;br /&gt;&lt;br /&gt;2 - Groovy makes it really easy to work with Regular Expressions.  No more pattern compiling.&lt;br /&gt;&lt;br /&gt;3.  The Groovy &lt;a href="http://groovy.codehaus.org/groovy-jdk.html#meth377"&gt;sum()&lt;/a&gt; extension means that we don't need to track the total number of matches, nor do we need to iterate through the HashMap at the end.&lt;br /&gt;&lt;br /&gt;All in all, I'm enjoying playing with Groovy at the moment.  I've found the barrier to entry to be pretty low.  It will be interesting to see how we continue to use Groovy in the future.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-7668038690722762260?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/7668038690722762260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=7668038690722762260' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/7668038690722762260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/7668038690722762260'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/08/using-groovy-to-grep-xml.html' title='Using Groovy to grep XML'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9072572603236462376.post-5484403653723034240</id><published>2007-08-13T23:36:00.001-07:00</published><updated>2007-10-05T23:26:41.520-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Design (TDD)'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Throw Away Code Must Be Thrown Away</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;From time to time, it’s advantageous to take off my TDD hat a fling a small bit of code.  I’ve found this is the quickest way to gain a bit of confidence in working with libraries that I haven’t touched before.  This allows me to be sure that I know how to interface with the functionality that I need.  After a quick proof-of-concept, I’ll know what parameters and classes are needed to get what I want.&lt;br /&gt;&lt;br /&gt;My own personal problem with this has been developing the discipline to remove the code from the system once I’ve figured out what I’m after.  Why do I think I need to discipline myself to do this?  Simply put, my worst code is always the code that wasn’t written “test-first.”  The spikes that I pull over into production code often cause problems when trying to get them under test coverage. &lt;br /&gt;&lt;br /&gt;Conversely, I’ve found that following Test Driven Development yields code that is easier to test and frankly, better designed.  TDD prevents a great deal of speculative development and over design.  Therefore, it’s much better to step back from the initial spike and start over by writing tests.&lt;br /&gt;&lt;br /&gt;I have found it much easier to prevent the spikes from getting attached to the project by putting them in a completely separate class.  Name it “class ThrowAway” to help yourself remember.&lt;br /&gt;&lt;br /&gt;Bottom line:  Throw-away code must be thrown away.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9072572603236462376-5484403653723034240?l=testinfected.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://testinfected.blogspot.com/feeds/5484403653723034240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9072572603236462376&amp;postID=5484403653723034240' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5484403653723034240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9072572603236462376/posts/default/5484403653723034240'/><link rel='alternate' type='text/html' href='http://testinfected.blogspot.com/2007/08/throw-away-code-must-be-thrown-away.html' title='Throw Away Code Must Be Thrown Away'/><author><name>Eric Anderson</name><uri>http://www.blogger.com/profile/18168464481506788498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
