<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Refactor Squad by the science department</title>
 
 <link href="http://refactorsquad.com/" />
 <updated>2009-05-07T12:04:28-07:00</updated>
 <id>http://refactorsquad.com/</id>
 <author>
   <name>Pat Maddox</name>
   <email>pat.maddox@scidept.com</email>
 </author>
 <author>
    <name>BJ Clark</name>
    <email>bjclark@scidept.com</email>
  </author>

 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/RefactorSquad" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="refactorsquad" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">RefactorSquad</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><entry>
   <title>Working Effectively With Legacy Rails Code Presentation</title>
   <link href="http://refactorsquad.com/2009/05/06/working-effectively-with-legacy-rails-code.html" />
   <updated>2009-05-06T00:00:00-07:00</updated>
   <id>http://refactorsquad.com/2009/05/06/working-effectively-with-legacy-rails-code</id>
   <content type="html">&lt;h3&gt;Slides&lt;/h3&gt;
&lt;div style="width:425px;text-align:left" id="__ss_1397041"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/scidept/working-effectively-with-legacy-code?type=presentation" title="Working Effectively With Legacy Code"&gt;Working Effectively With Legacy Code&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=workingeffectivelywithlegacycode-090506183833-phpapp02&amp;rel=0&amp;stripped_title=working-effectively-with-legacy-code" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=workingeffectivelywithlegacycode-090506183833-phpapp02&amp;rel=0&amp;stripped_title=working-effectively-with-legacy-code" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/scidept"&gt;scidept&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;The code is hosted on &lt;a href="http://github.com/pat-maddox/legacy_preso/tree/master"&gt;GitHub&lt;/a&gt; for you to download/fork. All the code we used in the presentation is there, and we&amp;#8217;d love your feedback.&lt;/p&gt;
&lt;h3&gt;Thanks&lt;/h3&gt;
&lt;p&gt;Thanks to everyone that came to the talk and those of you that asked questions. It was a great discussion and we had a great time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Using Fixjour for Fun and Profit</title>
   <link href="http://refactorsquad.com/2009/05/02/using-fixjour-for-fun-and-profit.html" />
   <updated>2009-05-02T00:00:00-07:00</updated>
   <id>http://refactorsquad.com/2009/05/02/using-fixjour-for-fun-and-profit</id>
   <content type="html">&lt;p&gt;When I first became test-infected, I did not give much thought to how I set up the objects used in the examples. Rails shipped with yaml fixtures, so I used those but would on occasion just make new instances when the setup was minimal. They looked something like this:&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;describe User do
  context &amp;quot;admin&amp;quot; do
    subject { User.new :admin =&amp;gt; true }

    it { should be_omniscient }
    it { should be_omnipotent }
  end

  context &amp;quot;regular user&amp;quot; do
    subject { User.new :admin =&amp;gt; false }

    it { should_not be_omniscient }
    it { should_not be_omnipotent }
  end
end&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Okay they didn&amp;#8217;t look exactly like that, I&amp;#8217;m taking advantage of &lt;a href='http://blog.davidchelimsky.net/2009/1/13/rspec-1-1-12-is-released/'&gt;RSpec&amp;#8217;s sweet implicit subject&lt;/a&gt; feature, but you can see that I&amp;#8217;ve just created a new instance and passed it some attributes.&lt;/p&gt;

&lt;p&gt;There are some problems with newing up objects like that. Often you will need a valid object, such as in an integration test that expects the record to be in the db. When you do, the test looks more like&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;describe User do
  context &amp;quot;admin&amp;quot; do
    subject { User.new :admin =&amp;gt; true, :name =&amp;gt; &amp;quot;Joe the Administrator&amp;quot;, :employee_id =&amp;gt; &amp;quot;abc123&amp;quot; }
    it { should be_omniscient }
    it { should be_omnipotent }
  end

  context &amp;quot;regular user&amp;quot; do
    subject { User.new :admin =&amp;gt; false, :name =&amp;gt; &amp;quot;Joe Schmo&amp;quot;, :employee_id =&amp;gt; &amp;quot;foobar&amp;quot; }

    it { should_not be_omniscient }
    it { should_not be_omnipotent }
  end
end&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The first problem is the newly required attributes make the example less clear. What is it that makes a User an admin? Is it the admin field, the name, or the employee id? You can be helpful and position the important attributes first, and use good naming conventions, but it would be nice to get rid of the noise.&lt;/p&gt;

&lt;p&gt;A much more painful problem that you &lt;em&gt;will&lt;/em&gt; experience soon is what happens when you add a new validation to the model. Specs start breaking all over the place because they&amp;#8217;re expecting a valid object. Now you get to go back and add the new field to every single example. No fun.&lt;/p&gt;

&lt;p&gt;It can be a good idea to separate object graph construction from use, but it&amp;#8217;s especially important in tests. As we just saw, failure to do so results in tests that are too tightly coupled to the implementation. You need to &lt;a href='http://nat.truemesh.com/archives/000714.html'&gt;build test data&lt;/a&gt; somehow. There are many different patterns, and &lt;a href='http://github.com/smtlaissezfaire/fixturereplacement/tree/master'&gt;lots of&lt;/a&gt; &lt;a href='http://github.com/thoughtbot/factory_girl/tree/master'&gt;different&lt;/a&gt; &lt;a href='http://github.com/flogic/object_daddy/tree/master'&gt;tools&lt;/a&gt; for Ruby. I&amp;#8217;m going to show you my favorite, &lt;a href='http://github.com/nakajima/fixjour/tree/master'&gt;Fixjour&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id='easy_fixture_setup'&gt;Easy fixture setup&lt;/h1&gt;

&lt;p&gt;When I say fixture, I mean an object you set up for use within a test, not the yaml files that Rails automatically loads into the db. I will refer to those as yaml fixtures or database fixtures - Rails hijacked the term fixture and I&amp;#8217;m taking it back :)&lt;/p&gt;

&lt;p&gt;Fixjour lets you easily define a builder for your models:&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;Fixjour do
  define_builder(User) { :name =&amp;gt; &amp;quot;Pat&amp;quot;, :admin =&amp;gt; false, :empid =&amp;gt; &amp;quot;abc123&amp;quot; }
end&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This gives you a few methods to build objects for your tests. Here are the examples from before, using Fixjour to do the setup:&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;describe User do
  context &amp;quot;admin&amp;quot; do
    subject { new_user :admin =&amp;gt; true }

    it { should be_omniscient }
    it { should be_omnipotent }
  end

  context &amp;quot;regular user&amp;quot; do
    subject { new_user :admin =&amp;gt; false }

    it { should_not be_omniscient }
    it { should_not be_omnipotent }
  end
end&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The new_user method returns a non-admin User named Pat, with an employee id of abc123. You can override options by passing them in, which is what I did with the admin field. The test makes it obvious that the admin field changes a User object&amp;#8217;s behavior, and now when adding validations, you will only have to modify the builder definition.&lt;/p&gt;

&lt;h1 id='tips'&gt;Tips&lt;/h1&gt;

&lt;p&gt;That&amp;#8217;s Fixjour at its simplest. Now I want to share some of my most used features, along with some general tips on setting up test data.&lt;/p&gt;

&lt;h2 id='new___create___valid_attributes'&gt;new_* / create_* / valid_&lt;em&gt;&lt;em&gt;attributes&lt;/em&gt;&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;In addition to the new_user method, defining a builder for User also gives us a create_user and valid_user_attributes method. new_user returns an unsaved object, whereas create_user will save it to the database before passing it back.&lt;/p&gt;

&lt;p&gt;valid_user_attributes returns a hash that you could pass to User.new and get a valid object. It&amp;#8217;s useful when you want an attributes hash rather than an object, such as testing the update action in a controller.&lt;/p&gt;

&lt;h2 id='hash_or_block_construction'&gt;Hash or block construction&lt;/h2&gt;

&lt;p&gt;When defining a builder, you can return a hash which Fixjour will then pass to the object&amp;#8217;s initialize, or you can build an object yourself. I already showed returning a hash. Here&amp;#8217;s an example of building the object. Notice that Fixjour yields the class that you&amp;#8217;re defining the builder for.&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;define_builder(User) do |klass|
  klass.new {:name =&amp;gt; &amp;quot;Pat&amp;quot;, :admin =&amp;gt; false, :empid =&amp;gt; &amp;quot;abc123&amp;quot;}
end&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I almost always use the hash form. Looks nicer to me. I only use the klass form when I have to do set up than just a simple hash, such as when I&amp;#8217;m adding objects to a has_many association.&lt;/p&gt;

&lt;h2 id='counters'&gt;Counters&lt;/h2&gt;

&lt;p&gt;You might have noticed that I&amp;#8217;m hard-coding values in the builder. That won&amp;#8217;t work in examples requiring multiple records, and you have a validates_uniqueness_of somewhere. You could use a Guid, but Fixjour provides counters that you can use to generate unique data.&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;define_builder(User) { :name =&amp;gt; &amp;quot;Pat&amp;quot;, :admin =&amp;gt; false, :empid =&amp;gt; &amp;quot;abc#{counter(:user)}&amp;quot; }&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;counter is just a simple incrementing counter, so if you call new_user a few times they&amp;#8217;ll all have different employee IDs. You can pass counter a name to scope the counts, so you could have counter(:user) increment separately from counter(:blog_post)&lt;/p&gt;

&lt;h2 id='associations'&gt;Associations&lt;/h2&gt;

&lt;p&gt;You can automatically set up associations by defining builders for each model and then calling one from the other.&lt;/p&gt;
&lt;div&gt;
  &lt;pre&gt;
    &lt;code class='ruby'&gt;define_builder(BlogPost)&lt;/code&gt;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='be_explicit_bee_explicit'&gt;Be explicit, be-e explicit&lt;/h2&gt;

&lt;p&gt;Look at the first Fixjour example I gave, where I define a builder that defaults the admin flag to false. When I want to test the admin behavior, I pass it in as false even though it&amp;#8217;s already set to false by default. This makes the test clearer by communicating the important components, and reduces coupling between tests and the test builder. If I don&amp;#8217;t pass it in, and down the road I change the default to true, the test will fail. This is part of the problem with Rails&amp;#8217;s built-in database fixtures. Each test that uses a particular fixture relies on the data within that fixture, and when you change that it ripples out to other tests, forcing you to tweak those tests or create a whole new set of fixtures.&lt;/p&gt;

&lt;p&gt;The important thing to remember is that you&amp;#8217;re just asking for a valid object - what&amp;#8217;s inside of it doesn&amp;#8217;t matter unless you explicitly set it. Keep that in mind whether you&amp;#8217;re using Fixjour or any other test data framework, and you should end up with more maintainable tests.&lt;/p&gt;

&lt;h1 id='where_to_go_from_here'&gt;Where to go from here&lt;/h1&gt;

&lt;p&gt;There&amp;#8217;s some good documentation at the &lt;a href='http://github.com/nakajima/fixjour/tree/master'&gt;Fixjour github repo&lt;/a&gt; so check it out.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
