<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.floehopper.org/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.floehopper.org/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>Floehopper</title>
  <subtitle type="html">thoughts on the bergy bits of life</subtitle>
  <id>tag:blog.floehopper.org,2005:Typo</id>
  <generator uri="http://www.typosphere.org" version="4.0">Typo</generator>
  
  <link href="http://blog.floehopper.org/" rel="alternate" type="text/html" />
  <updated>2008-04-05T00:23:50+00:00</updated>
  <link rel="self" href="http://feeds.floehopper.org/floehopper-blog" type="application/atom+xml" /><entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:3aa53475-6a90-4cf6-915b-ff8804ff5d61</id>
    <published>2008-04-05T00:10:06+00:00</published>
    <updated>2008-04-05T00:23:50+00:00</updated>
    <title type="html">Nasty Ruby Bug Affecting Test::Unit</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/264288296/nasty-ruby-bug-affecting-test-unit" rel="alternate" type="text/html" />
    <category term="ruby" scheme="http://blog.floehopper.org/articles/tag/ruby" />
    <category term="bug" scheme="http://blog.floehopper.org/articles/tag/bug" />
    <category term="test" scheme="http://blog.floehopper.org/articles/tag/test" />
    <category term="unit" scheme="http://blog.floehopper.org/articles/tag/unit" />
    <category term="exit" scheme="http://blog.floehopper.org/articles/tag/exit" />
    <category term="code" scheme="http://blog.floehopper.org/articles/tag/code" />
    <category term="hook" scheme="http://blog.floehopper.org/articles/tag/hook" />
    <category term="testing" scheme="http://blog.floehopper.org/articles/tag/testing" />
    <category term="continuous" scheme="http://blog.floehopper.org/articles/tag/continuous" />
    <category term="integration" scheme="http://blog.floehopper.org/articles/tag/integration" />
    <summary type="html">&lt;h3 id="introduction"&gt;Introduction&lt;/h3&gt;


	&lt;p&gt;Some time ago, while I was pair-programming with him, &lt;a href="http://blog.seagul.co.uk"&gt;Chris&lt;/a&gt; alerted me to a &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; bug he&amp;#8217;d come across which was interfering with the diagnosis of a bug in our application. Since then I&amp;#8217;ve tried to find out more about it, but couldn&amp;#8217;t find much, so I&amp;#8217;ve done a bit of investigation and thought I&amp;#8217;d post it here in case it&amp;#8217;s useful to anyone else. The bug has long since been fixed, but I&amp;#8217;m sure there are still people our there with the &lt;a href="#affected-versions"&gt;affected versions&lt;/a&gt; of Ruby 1.8.6.&lt;/p&gt;


	&lt;h3 id="ruby-bug"&gt;Ruby bug&lt;/h3&gt;


	&lt;p&gt;As far as I understand it, the bug is in Ruby&amp;#8217;s &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005958"&gt;&lt;code&gt;Kernel.at_exit&lt;/code&gt;&lt;/a&gt; hook. A call to &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005956"&gt;&lt;code&gt;Kernel.exit(false)&lt;/code&gt;&lt;/a&gt; should cause the process to exit with an &lt;strong&gt;exit status of 1&lt;/strong&gt; indicating the process did not complete successfully. The bug means that calling &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005956"&gt;&lt;code&gt;Kernel.exit(false)&lt;/code&gt;&lt;/a&gt; from within &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005958"&gt;&lt;code&gt;Kernel.at_exit&lt;/code&gt;&lt;/a&gt; incorrectly causes the process to exit with an &lt;strong&gt;exit status of 0&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;The most relevant bug report is &lt;a href="http://rubyforge.org/tracker/?func=detail&amp;#38;atid=1698&amp;#38;aid=9300&amp;#38;group_id=426"&gt;#9300&lt;/a&gt; and the most relevant mailing list thread is made up of:- &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/10746"&gt;[ruby-core:10746]&lt;/a&gt;, &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/10748"&gt;[ruby-core:10748]&lt;/a&gt;, &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/10760"&gt;[ruby-core:10760]&lt;/a&gt;.&lt;/p&gt;


The fix seems to be in changeset 12126&amp;#8230;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;r12126 | nobu | 2007-03-23 16:53:42 +0000 (Fri, 23 Mar 2007) | 9 lines

* eval.c (ruby_cleanup): exit by SystemExit and SignalException in END
  block.  [ruby-core:10609]

* test/ruby/test_beginendblock.rb (test_should_propagate_exit_code):
  test for exit in END block.  [ruby-core:10760]

* test/ruby/test_beginendblock.rb (test_should_propagate_signaled):
  test for signal in END block.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 class="implications"&gt;Implications for Test::Unit &amp;#38; Rake::TestTask&lt;/h3&gt;


	&lt;p&gt;The &lt;a href="#ruby-bug"&gt;bug&lt;/a&gt; has some important consequences. &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;&lt;code&gt;Test::Unit&lt;/code&gt;&lt;/a&gt; makes use of this mechanism to report test failures. Unfortunately, the bug means that a &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;&lt;code&gt;Test::Unit&lt;/code&gt;&lt;/a&gt; process will always return an &lt;strong&gt;exit status of 0&lt;/strong&gt; even when there have been test failures.&lt;/p&gt;


From &lt;code&gt;test/unit.rb&lt;/code&gt;:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;at_exit&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="global"&gt;$!&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run?&lt;/span&gt;
    &lt;span class="ident"&gt;exit&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;AutoRunner&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;This in turn means that a &lt;a href="http://rake.rubyforge.org/classes/Rake/TestTask.html"&gt;&lt;code&gt;Rake::TestTask&lt;/code&gt;&lt;/a&gt; process will also always return an &lt;strong&gt;exit status of 0&lt;/strong&gt; even when there have been test failures. This is significant, because many &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration&lt;/a&gt; systems rely on &lt;a href="http://rake.rubyforge.org/classes/Rake/TestTask.html"&gt;&lt;code&gt;Rake::TestTask&lt;/code&gt;&lt;/a&gt; processes returning an &lt;strong&gt;exit status of 1&lt;/strong&gt; to indicate that there have been test failures. Thus you will get false positive passing builds &amp;#8211; not good.&lt;/p&gt;


	&lt;h3 id="affected-versions"&gt;Affected versions of Ruby&lt;/h3&gt;


	&lt;p&gt;I&amp;#8217;ve built and installed a number of versions of Ruby and run tests on them to try to establish which ones are affected. Although they aren&amp;#8217;t comprehensive, here are the results&amp;#8230;&lt;/p&gt;


	&lt;table&gt;
		&lt;tr style="background:#ddd;"&gt;
			&lt;td&gt; affected? &lt;/td&gt;
			&lt;td&gt; version &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.4 (2005-12-24) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.5 (2006-08-25) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.5 (2007-03-16 patchlevel 37) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.5 (2008-03-03 patchlevel 115) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-02-17 patchlevel 0) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-03-16 patchlevel 2) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-03-19 patchlevel 4) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 5) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 6) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 7) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 8) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-23 patchlevel 9) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-23 patchlevel 10) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-08-22 patchlevel 50) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.9.0 (2007-11-28 patchlevel 0) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;</summary>
    <content type="html">&lt;h3 id="introduction"&gt;Introduction&lt;/h3&gt;


	&lt;p&gt;Some time ago, while I was pair-programming with him, &lt;a href="http://blog.seagul.co.uk"&gt;Chris&lt;/a&gt; alerted me to a &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; bug he&amp;#8217;d come across which was interfering with the diagnosis of a bug in our application. Since then I&amp;#8217;ve tried to find out more about it, but couldn&amp;#8217;t find much, so I&amp;#8217;ve done a bit of investigation and thought I&amp;#8217;d post it here in case it&amp;#8217;s useful to anyone else. The bug has long since been fixed, but I&amp;#8217;m sure there are still people our there with the &lt;a href="#affected-versions"&gt;affected versions&lt;/a&gt; of Ruby 1.8.6.&lt;/p&gt;


	&lt;h3 id="ruby-bug"&gt;Ruby bug&lt;/h3&gt;


	&lt;p&gt;As far as I understand it, the bug is in Ruby&amp;#8217;s &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005958"&gt;&lt;code&gt;Kernel.at_exit&lt;/code&gt;&lt;/a&gt; hook. A call to &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005956"&gt;&lt;code&gt;Kernel.exit(false)&lt;/code&gt;&lt;/a&gt; should cause the process to exit with an &lt;strong&gt;exit status of 1&lt;/strong&gt; indicating the process did not complete successfully. The bug means that calling &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005956"&gt;&lt;code&gt;Kernel.exit(false)&lt;/code&gt;&lt;/a&gt; from within &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005958"&gt;&lt;code&gt;Kernel.at_exit&lt;/code&gt;&lt;/a&gt; incorrectly causes the process to exit with an &lt;strong&gt;exit status of 0&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;The most relevant bug report is &lt;a href="http://rubyforge.org/tracker/?func=detail&amp;#38;atid=1698&amp;#38;aid=9300&amp;#38;group_id=426"&gt;#9300&lt;/a&gt; and the most relevant mailing list thread is made up of:- &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/10746"&gt;[ruby-core:10746]&lt;/a&gt;, &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/10748"&gt;[ruby-core:10748]&lt;/a&gt;, &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/10760"&gt;[ruby-core:10760]&lt;/a&gt;.&lt;/p&gt;


The fix seems to be in changeset 12126&amp;#8230;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;r12126 | nobu | 2007-03-23 16:53:42 +0000 (Fri, 23 Mar 2007) | 9 lines

* eval.c (ruby_cleanup): exit by SystemExit and SignalException in END
  block.  [ruby-core:10609]

* test/ruby/test_beginendblock.rb (test_should_propagate_exit_code):
  test for exit in END block.  [ruby-core:10760]

* test/ruby/test_beginendblock.rb (test_should_propagate_signaled):
  test for signal in END block.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 class="implications"&gt;Implications for Test::Unit &amp;#38; Rake::TestTask&lt;/h3&gt;


	&lt;p&gt;The &lt;a href="#ruby-bug"&gt;bug&lt;/a&gt; has some important consequences. &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;&lt;code&gt;Test::Unit&lt;/code&gt;&lt;/a&gt; makes use of this mechanism to report test failures. Unfortunately, the bug means that a &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;&lt;code&gt;Test::Unit&lt;/code&gt;&lt;/a&gt; process will always return an &lt;strong&gt;exit status of 0&lt;/strong&gt; even when there have been test failures.&lt;/p&gt;


From &lt;code&gt;test/unit.rb&lt;/code&gt;:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;at_exit&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="global"&gt;$!&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run?&lt;/span&gt;
    &lt;span class="ident"&gt;exit&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;AutoRunner&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;This in turn means that a &lt;a href="http://rake.rubyforge.org/classes/Rake/TestTask.html"&gt;&lt;code&gt;Rake::TestTask&lt;/code&gt;&lt;/a&gt; process will also always return an &lt;strong&gt;exit status of 0&lt;/strong&gt; even when there have been test failures. This is significant, because many &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration&lt;/a&gt; systems rely on &lt;a href="http://rake.rubyforge.org/classes/Rake/TestTask.html"&gt;&lt;code&gt;Rake::TestTask&lt;/code&gt;&lt;/a&gt; processes returning an &lt;strong&gt;exit status of 1&lt;/strong&gt; to indicate that there have been test failures. Thus you will get false positive passing builds &amp;#8211; not good.&lt;/p&gt;


	&lt;h3 id="affected-versions"&gt;Affected versions of Ruby&lt;/h3&gt;


	&lt;p&gt;I&amp;#8217;ve built and installed a number of versions of Ruby and run tests on them to try to establish which ones are affected. Although they aren&amp;#8217;t comprehensive, here are the results&amp;#8230;&lt;/p&gt;


	&lt;table&gt;
		&lt;tr style="background:#ddd;"&gt;
			&lt;td&gt; affected? &lt;/td&gt;
			&lt;td&gt; version &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.4 (2005-12-24) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.5 (2006-08-25) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.5 (2007-03-16 patchlevel 37) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.5 (2008-03-03 patchlevel 115) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-02-17 patchlevel 0) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-03-16 patchlevel 2) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-03-19 patchlevel 4) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 5) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 6) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:red;"&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;Y&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 7) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-22 patchlevel 8) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-23 patchlevel 9) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-05-23 patchlevel 10) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.8.6 (2007-08-22 patchlevel 50) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:center;"&gt;&lt;code&gt;N&lt;/code&gt; &lt;/td&gt;
			&lt;td&gt; &lt;code&gt;ruby 1.9.0 (2007-11-28 patchlevel 0) [i686-darwin8.10.3]&lt;/code&gt; &lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/264288296" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/04/05/nasty-ruby-bug-affecting-test-unit</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:11955d9f-4314-46f7-b708-dca8b3860930</id>
    <published>2008-03-29T19:05:00+00:00</published>
    <updated>2008-03-29T19:10:18+00:00</updated>
    <title type="html">Prefer Commit Notes over Comments</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/260369627/prefer-commit-notes-over-comments" rel="alternate" type="text/html" />
    <category term="version" scheme="http://blog.floehopper.org/articles/tag/version" />
    <category term="control" scheme="http://blog.floehopper.org/articles/tag/control" />
    <category term="commit" scheme="http://blog.floehopper.org/articles/tag/commit" />
    <category term="note" scheme="http://blog.floehopper.org/articles/tag/note" />
    <category term="changeset" scheme="http://blog.floehopper.org/articles/tag/changeset" />
    <category term="svn" scheme="http://blog.floehopper.org/articles/tag/svn" />
    <category term="vcs" scheme="http://blog.floehopper.org/articles/tag/vcs" />
    <category term="comment" scheme="http://blog.floehopper.org/articles/tag/comment" />
    <category term="why" scheme="http://blog.floehopper.org/articles/tag/why" />
    <category term="what" scheme="http://blog.floehopper.org/articles/tag/what" />
    <summary type="html">&lt;p&gt;My colleague, &lt;a href="http://blog.seagul.co.uk/"&gt;Chris&lt;/a&gt;, recently posted about &lt;a href="http://blog.seagul.co.uk/articles/2008/03/28/version-control-commit-note-best-practice-or-not-you-decide"&gt;what makes a good commit note&lt;/a&gt;. His main point is that a good commit note should explain &lt;strong&gt;why&lt;/strong&gt; the changeset exists rather than &lt;strong&gt;what&lt;/strong&gt; it contains (which should be more self-evident). I agree with this and (as Chris mentions) it&amp;#8217;s of particular benefit when you have to do some software archeology. I&amp;#8217;d go a step further and say that, for me, the best commit notes express the &lt;em&gt;business&lt;/em&gt; reason for the changeset. If as a developer you are struggling to explain the business case for a particular change, (imho) you should try to find out before committing &amp;#8211; otherwise how do you know the changeset is delivering value to the business?&lt;/p&gt;


	&lt;p&gt;In a previous post about &lt;a href="http://blog.floehopper.org/articles/2007/05/10/prefer-tests-over-comments"&gt;preferring tests over comments&lt;/a&gt;, I expressed similar sentiments about using comments and tests to explain &lt;strong&gt;why&lt;/strong&gt; rather than &lt;strong&gt;what&lt;/strong&gt;. Chris&amp;#8217; post prompted me to re-read that old post and I noticed that it didn&amp;#8217;t explain why I &lt;a href="http://blog.floehopper.org/articles/2007/05/10/prefer-tests-over-comments"&gt;prefer tests over comments&lt;/a&gt;. The reason is that comments have a nasty habit of becoming out-of-date and getting left lying around to confuse the unwary, whereas you are forced to keep tests up-to-date (assuming they are part of a &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration build&lt;/a&gt;). For similar reasons I also think that commit notes are better than code comments, because they are forever associated with a snapshot of the code at the time they were written &amp;#8211; leaving less scope for confusion.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;My colleague, &lt;a href="http://blog.seagul.co.uk/"&gt;Chris&lt;/a&gt;, recently posted about &lt;a href="http://blog.seagul.co.uk/articles/2008/03/28/version-control-commit-note-best-practice-or-not-you-decide"&gt;what makes a good commit note&lt;/a&gt;. His main point is that a good commit note should explain &lt;strong&gt;why&lt;/strong&gt; the changeset exists rather than &lt;strong&gt;what&lt;/strong&gt; it contains (which should be more self-evident). I agree with this and (as Chris mentions) it&amp;#8217;s of particular benefit when you have to do some software archeology. I&amp;#8217;d go a step further and say that, for me, the best commit notes express the &lt;em&gt;business&lt;/em&gt; reason for the changeset. If as a developer you are struggling to explain the business case for a particular change, (imho) you should try to find out before committing &amp;#8211; otherwise how do you know the changeset is delivering value to the business?&lt;/p&gt;


	&lt;p&gt;In a previous post about &lt;a href="http://blog.floehopper.org/articles/2007/05/10/prefer-tests-over-comments"&gt;preferring tests over comments&lt;/a&gt;, I expressed similar sentiments about using comments and tests to explain &lt;strong&gt;why&lt;/strong&gt; rather than &lt;strong&gt;what&lt;/strong&gt;. Chris&amp;#8217; post prompted me to re-read that old post and I noticed that it didn&amp;#8217;t explain why I &lt;a href="http://blog.floehopper.org/articles/2007/05/10/prefer-tests-over-comments"&gt;prefer tests over comments&lt;/a&gt;. The reason is that comments have a nasty habit of becoming out-of-date and getting left lying around to confuse the unwary, whereas you are forced to keep tests up-to-date (assuming they are part of a &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration build&lt;/a&gt;). For similar reasons I also think that commit notes are better than code comments, because they are forever associated with a snapshot of the code at the time they were written &amp;#8211; leaving less scope for confusion.&lt;/p&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/260369627" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/03/29/prefer-commit-notes-over-comments</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:a40a74e5-5040-4345-951d-6f4a98be5e23</id>
    <published>2008-03-17T09:23:26+00:00</published>
    <updated>2008-03-17T09:35:53+00:00</updated>
    <title type="html">Java Rehabilitation Clinic</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/252886570/java-rehabilitation-clinic" rel="alternate" type="text/html" />
    <category term="java" scheme="http://blog.floehopper.org/articles/tag/java" />
    <category term="rehab" scheme="http://blog.floehopper.org/articles/tag/rehab" />
    <category term="clinic" scheme="http://blog.floehopper.org/articles/tag/clinic" />
    <category term="ruby" scheme="http://blog.floehopper.org/articles/tag/ruby" />
    <category term="thoughtworks" scheme="http://blog.floehopper.org/articles/tag/thoughtworks" />
    <summary type="html">&lt;p&gt;Not long after &lt;a href="http://www.techbelly.com"&gt;Ben&lt;/a&gt; persuaded me to join the fledgling &lt;a href="http://www.reevoo.com"&gt;Reevoo&lt;/a&gt;, we got our first big ReevooMark partners (&lt;a href="http://www.dixons.co.uk"&gt;Dixons&lt;/a&gt; &amp;#38; &lt;a href="http://www.currys.co.uk"&gt;Currys&lt;/a&gt;) live. To celebrate this event and my having left Java behind at &lt;a href="http://www.thoughtworks.co.uk"&gt;Thoughtworks&lt;/a&gt;, Ben bought me a &lt;a href="http://www.cafepress.com/javarehab.29832584"&gt;Java Rehabilitation Clinic mug&lt;/a&gt;. The mug has recently developed a crack. I wonder if it&amp;#8217;s trying to tell me it&amp;#8217;s time to learn another language&amp;#8230;&lt;/p&gt;


&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2329269226"&gt;&lt;img src="http://farm3.static.flickr.com/2213/2329269226_6fc5b864c1_s.jpg" width="75" height="75" alt="java-rehab-clinic-mug" title="java-rehab-clinic-mug"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:75px"&gt;Java Rehabilitation Clinic mug&lt;/p&gt;&lt;/div&gt;</summary>
    <content type="html">&lt;p&gt;Not long after &lt;a href="http://www.techbelly.com"&gt;Ben&lt;/a&gt; persuaded me to join the fledgling &lt;a href="http://www.reevoo.com"&gt;Reevoo&lt;/a&gt;, we got our first big ReevooMark partners (&lt;a href="http://www.dixons.co.uk"&gt;Dixons&lt;/a&gt; &amp;#38; &lt;a href="http://www.currys.co.uk"&gt;Currys&lt;/a&gt;) live. To celebrate this event and my having left Java behind at &lt;a href="http://www.thoughtworks.co.uk"&gt;Thoughtworks&lt;/a&gt;, Ben bought me a &lt;a href="http://www.cafepress.com/javarehab.29832584"&gt;Java Rehabilitation Clinic mug&lt;/a&gt;. The mug has recently developed a crack. I wonder if it&amp;#8217;s trying to tell me it&amp;#8217;s time to learn another language&amp;#8230;&lt;/p&gt;


&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2329269226"&gt;&lt;img src="http://farm3.static.flickr.com/2213/2329269226_6fc5b864c1_s.jpg" width="75" height="75" alt="java-rehab-clinic-mug" title="java-rehab-clinic-mug"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:75px"&gt;Java Rehabilitation Clinic mug&lt;/p&gt;&lt;/div&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/252886570" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/03/17/java-rehabilitation-clinic</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:d04659dc-9918-4e46-8387-35eb394e538f</id>
    <published>2008-03-13T09:48:22+00:00</published>
    <updated>2008-03-13T09:48:22+00:00</updated>
    <title type="html">Remote Pair Programming</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/250675423/remote-pair-programming" rel="alternate" type="text/html" />
    <category term="pair" scheme="http://blog.floehopper.org/articles/tag/pair" />
    <category term="programming" scheme="http://blog.floehopper.org/articles/tag/programming" />
    <category term="agile" scheme="http://blog.floehopper.org/articles/tag/agile" />
    <category term="xp" scheme="http://blog.floehopper.org/articles/tag/xp" />
    <category term="gnu" scheme="http://blog.floehopper.org/articles/tag/gnu" />
    <category term="screen" scheme="http://blog.floehopper.org/articles/tag/screen" />
    <category term="vnc" scheme="http://blog.floehopper.org/articles/tag/vnc" />
    <category term="skype" scheme="http://blog.floehopper.org/articles/tag/skype" />
    <category term="osx" scheme="http://blog.floehopper.org/articles/tag/osx" />
    <category term="terminal" scheme="http://blog.floehopper.org/articles/tag/terminal" />
    <summary type="html">&lt;p&gt;A while ago, &lt;a href="http://blog.seagul.co.uk/"&gt;Chris&lt;/a&gt; mentioned that &lt;a href="http://blog.seagul.co.uk/articles/2007/09/29/monitoring-the-mac-osx-filesystem-with-ruby"&gt;we&amp;#8217;ve been trying out a few ideas&lt;/a&gt; for making remote &lt;a href="http://www.extremeprogramming.org/rules/pair.html"&gt;pair-programming&lt;/a&gt; easier. We&amp;#8217;ve been doing quite a bit more remote pairing recently. Most of the time we just use a combination of &lt;a href="http://en.wikipedia.org/wiki/VNC"&gt;&lt;span class="caps"&gt;VNC&lt;/span&gt;&lt;/a&gt; (I&amp;#8217;ve been using &lt;a href="http://www.redstonesoftware.com/products/vine/server/vineosx/index.html"&gt;Vine Server&lt;/a&gt;) and voice over &lt;a href="http://www.skype.com/"&gt;Skype&lt;/a&gt; (using a headset really helps).&lt;/p&gt;


	&lt;p&gt;But something else we&amp;#8217;ve used successfully is multi-user &lt;a href="http://www.gnu.org/software/screen/"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; screen&lt;/a&gt; sessions. The advantage of this technique is that much less bandwidth is required and the terminal is much more responsive. I thought I&amp;#8217;d post the magic incantation we&amp;#8217;ve been using (on &lt;a href="http://en.wikipedia.org/wiki/Mac_OS_X"&gt;&lt;span class="caps"&gt;OSX&lt;/span&gt;&lt;/a&gt;), in case anyone else finds it useful&amp;#8230;&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;  # on the server
  sudo chmod u+s /usr/bin/screen

  # first user connects to server over ssh and runs the following
  screen -S &amp;lt;session_name&amp;gt;
  ctrl-A :multiuser on
  ctrl-A :acladd &amp;lt;client_username&amp;gt;

  # second user connects to server over ssh and runs the following
  screen -x &amp;lt;server_username&amp;gt;/&amp;lt;session_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary>
    <content type="html">&lt;p&gt;A while ago, &lt;a href="http://blog.seagul.co.uk/"&gt;Chris&lt;/a&gt; mentioned that &lt;a href="http://blog.seagul.co.uk/articles/2007/09/29/monitoring-the-mac-osx-filesystem-with-ruby"&gt;we&amp;#8217;ve been trying out a few ideas&lt;/a&gt; for making remote &lt;a href="http://www.extremeprogramming.org/rules/pair.html"&gt;pair-programming&lt;/a&gt; easier. We&amp;#8217;ve been doing quite a bit more remote pairing recently. Most of the time we just use a combination of &lt;a href="http://en.wikipedia.org/wiki/VNC"&gt;&lt;span class="caps"&gt;VNC&lt;/span&gt;&lt;/a&gt; (I&amp;#8217;ve been using &lt;a href="http://www.redstonesoftware.com/products/vine/server/vineosx/index.html"&gt;Vine Server&lt;/a&gt;) and voice over &lt;a href="http://www.skype.com/"&gt;Skype&lt;/a&gt; (using a headset really helps).&lt;/p&gt;


	&lt;p&gt;But something else we&amp;#8217;ve used successfully is multi-user &lt;a href="http://www.gnu.org/software/screen/"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; screen&lt;/a&gt; sessions. The advantage of this technique is that much less bandwidth is required and the terminal is much more responsive. I thought I&amp;#8217;d post the magic incantation we&amp;#8217;ve been using (on &lt;a href="http://en.wikipedia.org/wiki/Mac_OS_X"&gt;&lt;span class="caps"&gt;OSX&lt;/span&gt;&lt;/a&gt;), in case anyone else finds it useful&amp;#8230;&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;  # on the server
  sudo chmod u+s /usr/bin/screen

  # first user connects to server over ssh and runs the following
  screen -S &amp;lt;session_name&amp;gt;
  ctrl-A :multiuser on
  ctrl-A :acladd &amp;lt;client_username&amp;gt;

  # second user connects to server over ssh and runs the following
  screen -x &amp;lt;server_username&amp;gt;/&amp;lt;session_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/250675423" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/03/13/remote-pair-programming</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:43e6745c-43d2-45e0-8561-310492a6c741</id>
    <published>2008-02-22T15:18:00+00:00</published>
    <updated>2008-02-22T18:47:12+00:00</updated>
    <title type="html">End of the Road?</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/239451843/end-of-the-road" rel="alternate" type="text/html" />
    <category term="mead" scheme="http://blog.floehopper.org/articles/tag/mead" />
    <category term="road" scheme="http://blog.floehopper.org/articles/tag/road" />
    <category term="sign" scheme="http://blog.floehopper.org/articles/tag/sign" />
    <category term="newyork" scheme="http://blog.floehopper.org/articles/tag/newyork" />
    <category term="usa" scheme="http://blog.floehopper.org/articles/tag/usa" />
    <summary type="html">&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2283275801"&gt;&lt;img src="http://farm3.static.flickr.com/2090/2283275801_393d150945.jpg" width="375" height="500" alt="Mead Road" title="Mead Road"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:375px"&gt;A road sign from up-state New York&lt;/p&gt;&lt;/div&gt;

	&lt;p&gt;The photo was taken by a friend of my sister on a recent trip to the States.&lt;/p&gt;</summary>
    <content type="html">&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2283275801"&gt;&lt;img src="http://farm3.static.flickr.com/2090/2283275801_393d150945.jpg" width="375" height="500" alt="Mead Road" title="Mead Road"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:375px"&gt;A road sign from up-state New York&lt;/p&gt;&lt;/div&gt;

	&lt;p&gt;The photo was taken by a friend of my sister on a recent trip to the States.&lt;/p&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/239451843" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/02/22/end-of-the-road</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:857791bb-b4ad-41c0-845d-69d0909d0b7c</id>
    <published>2008-02-17T18:10:01+00:00</published>
    <updated>2008-02-17T18:15:15+00:00</updated>
    <title type="html">Mocking in Java using Mocha</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/236584239/mocking-in-java-using-mocha" rel="alternate" type="text/html" />
    <category term="java" scheme="http://blog.floehopper.org/articles/tag/java" />
    <category term="ruby" scheme="http://blog.floehopper.org/articles/tag/ruby" />
    <category term="mocha" scheme="http://blog.floehopper.org/articles/tag/mocha" />
    <category term="test" scheme="http://blog.floehopper.org/articles/tag/test" />
    <category term="mock" scheme="http://blog.floehopper.org/articles/tag/mock" />
    <summary type="html">&lt;p&gt;&lt;a href="http://ola-bini.blogspot.com/"&gt;Ola Bini&lt;/a&gt; one of the &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; guys has released the &lt;a href="http://jtestr.codehaus.org/"&gt;JtestR&lt;/a&gt; tool which allows you to write tests for &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; code in &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;! Ola has bundled a number of Ruby libraries &amp;#8211; &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt;, &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;, &lt;a href="http://dust.rubyforge.org/"&gt;Dust&lt;/a&gt;, &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;Test::Unit&lt;/a&gt; &amp;#38; &lt;a href="http://rubyforge.org/projects/activesupport/"&gt;ActiveSupport&lt;/a&gt; &amp;#8211; together with JRuby to allow you to write Ruby test cases that test Java code.&lt;/p&gt;


	&lt;p&gt;He has a couple of examples in the &lt;a href="http://jtestr.codehaus.org/Mocks"&gt;Mock documentation&lt;/a&gt; of how to use &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt;...&lt;/p&gt;


	&lt;p&gt;The first one demonstrates using &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt; to mock an interface (&lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Map.html"&gt;Map&lt;/a&gt;).&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Map&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Iterator&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Set&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;HashMap&lt;/span&gt;

  &lt;span class="ident"&gt;functional_tests&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
    &lt;span class="ident"&gt;test&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;that a new HashMap can be created based on another map&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
      &lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:size&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;iter&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Iterator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:hasNext&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;set&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:iterator&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:entrySet&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;assert_equals&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;HashMap&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The second example demonstrates using &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt; to setup expectations on a real (non-mock) instance (&lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html"&gt;HashMap&lt;/a&gt;)...&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Iterator&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Set&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;HashMap&lt;/span&gt;

  &lt;span class="ident"&gt;functional_tests&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
    &lt;span class="ident"&gt;test&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;that a new HashMap can be created based on another map&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
      &lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;HashMap&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:size&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;iter&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Iterator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:hasNext&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;set&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:iterator&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:entrySet&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;assert_equals&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;HashMap&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary>
    <content type="html">&lt;p&gt;&lt;a href="http://ola-bini.blogspot.com/"&gt;Ola Bini&lt;/a&gt; one of the &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; guys has released the &lt;a href="http://jtestr.codehaus.org/"&gt;JtestR&lt;/a&gt; tool which allows you to write tests for &lt;a href="http://java.sun.com/"&gt;Java&lt;/a&gt; code in &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;! Ola has bundled a number of Ruby libraries &amp;#8211; &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt;, &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;, &lt;a href="http://dust.rubyforge.org/"&gt;Dust&lt;/a&gt;, &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;Test::Unit&lt;/a&gt; &amp;#38; &lt;a href="http://rubyforge.org/projects/activesupport/"&gt;ActiveSupport&lt;/a&gt; &amp;#8211; together with JRuby to allow you to write Ruby test cases that test Java code.&lt;/p&gt;


	&lt;p&gt;He has a couple of examples in the &lt;a href="http://jtestr.codehaus.org/Mocks"&gt;Mock documentation&lt;/a&gt; of how to use &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt;...&lt;/p&gt;


	&lt;p&gt;The first one demonstrates using &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt; to mock an interface (&lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Map.html"&gt;Map&lt;/a&gt;).&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Map&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Iterator&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Set&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;HashMap&lt;/span&gt;

  &lt;span class="ident"&gt;functional_tests&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
    &lt;span class="ident"&gt;test&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;that a new HashMap can be created based on another map&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
      &lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:size&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;iter&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Iterator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:hasNext&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;set&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:iterator&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:entrySet&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;assert_equals&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;HashMap&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The second example demonstrates using &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt; to setup expectations on a real (non-mock) instance (&lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html"&gt;HashMap&lt;/a&gt;)...&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Iterator&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Set&lt;/span&gt;
  &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;util&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;HashMap&lt;/span&gt;

  &lt;span class="ident"&gt;functional_tests&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
    &lt;span class="ident"&gt;test&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;that a new HashMap can be created based on another map&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; 
      &lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;HashMap&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:size&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;iter&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Iterator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:hasNext&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;set&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:iterator&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;iter&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expects&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:entrySet&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

      &lt;span class="ident"&gt;assert_equals&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;HashMap&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/236584239" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/02/17/mocking-in-java-using-mocha</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:b25e1f77-525e-4a6c-97a8-56c8e364f7a0</id>
    <published>2008-01-04T22:37:22+00:00</published>
    <updated>2008-01-04T22:56:42+00:00</updated>
    <title type="html">More GNER/NXEC Advance Single tickets shenanigans</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/211354824/more-gner-nxec-advance-single-tickets-shenanigans" rel="alternate" type="text/html" />
    <category term="nxec" scheme="http://blog.floehopper.org/articles/tag/nxec" />
    <category term="gner" scheme="http://blog.floehopper.org/articles/tag/gner" />
    <category term="advance" scheme="http://blog.floehopper.org/articles/tag/advance" />
    <category term="single" scheme="http://blog.floehopper.org/articles/tag/single" />
    <category term="ticket" scheme="http://blog.floehopper.org/articles/tag/ticket" />
    <summary type="html">&lt;p&gt;As is &lt;a href="http://blog.floehopper.org/articles/2007/10/29/changing-gner-advance-single-tickets"&gt;so often&lt;/a&gt; &lt;a href="http://blog.floehopper.org/articles/2007/11/08/changing-gner-advance-single-tickets-reply"&gt;the case&lt;/a&gt;, today I wanted to change the date of some of my &lt;span class="caps"&gt;GNER&lt;/span&gt; Advance Single tickets. I&amp;#8217;ve never written down the phone number of the &lt;a href="http://getsatisfaction.com/gner"&gt;&lt;span class="caps"&gt;GNER&lt;/span&gt;&lt;/a&gt; website support team, so I looked at a couple of the old &lt;span class="caps"&gt;GNER&lt;/span&gt; URLs to see if I could find it.&lt;/p&gt;


	&lt;p&gt;Skip ahead to &lt;a href="#the-nub-of-the-matter"&gt;The Nub of the Matter&lt;/a&gt; if you&amp;#8217;re not very interested in the gory details.&lt;/p&gt;


	&lt;h3&gt;From Pillar to Post&lt;/h3&gt;


&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2166535107"&gt;&lt;img src="http://farm3.static.flickr.com/2301/2166535107_a3109f1bf5.jpg" width="500" height="133" alt="gner-weve-moved" title="gner-weve-moved"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:500px"&gt;www.gner.co.uk - redirects to NXEC website and gives no phone number&lt;/p&gt;&lt;/div&gt;

&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2167328154"&gt;&lt;img src="http://farm3.static.flickr.com/2357/2167328154_f74a04d868.jpg" width="500" height="332" alt="gnertickets-weve-moved" title="gnertickets-weve-moved"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:500px"&gt;www.gnertickets.co.uk - gives the number 08457225111&lt;/p&gt;&lt;/div&gt;

	&lt;p&gt;So I rang 08457225111. It was the &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; customer support number. I waited on hold for a few minutes and pressed a number of option buttons as is the way of things. Eventually I spoke to a human being and asked whether they could change my tickets. They said they couldn&amp;#8217;t, but that I should ring 08700101127. So I did. This turned out to be the Virgin customer support number. After the obligatory wait and button pushing, I spoke to a human who told me I had been given the wrong number. I was given a new number &amp;#8211; 08457225225 (option #2, followed by option #4).&lt;/p&gt;


	&lt;p&gt;This got me back to &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; and which was decidedly annoying. They then gave me another number (08700101296) which they said was for &amp;#8220;The Train Line&amp;#8221; who apparently used to run the &lt;span class="caps"&gt;GNER&lt;/span&gt; website. However when I got through to them, they denied all knowledge and gave me yet another number &amp;#8211; 08703665990. This finally got me through to &lt;span class="caps"&gt;GNER&lt;/span&gt; &amp;#8211; hooray!&lt;/p&gt;


	&lt;p&gt;I was worried that there would be complications, because the new tickets would have to be issued by &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt;, whereas the old tickets were issued by &lt;a href="http://getsatisfaction.com/gner"&gt;&lt;span class="caps"&gt;GNER&lt;/span&gt;&lt;/a&gt;. But I was pleasantly surprised to be able to change my &lt;span class="caps"&gt;GNER&lt;/span&gt; Advance Single tickets with no more pain than normal (which included giving my credit card details three times &amp;#8211; once for each ticket &amp;#8211; doh!). In fact the rep I spoke to was remarkably efficient.&lt;/p&gt;


	&lt;p&gt;So there goes another pointless hour of my life&amp;#8230;&lt;/p&gt;


	&lt;h3 id="the-nub-of-the-matter"&gt;The Nub of the Matter&lt;/h3&gt;


If you want to change tickets purchased through:
	&lt;ul&gt;
	&lt;li&gt;the &lt;strong&gt;old&lt;/strong&gt; GNER website &amp;#8211; then ring 08703665990&lt;/li&gt;
		&lt;li&gt;the &lt;strong&gt;new&lt;/strong&gt; (but rather transient) &lt;span class="caps"&gt;GNER&lt;/span&gt; website &amp;#8211; then ring 08547225111&lt;/li&gt;
		&lt;li&gt;the &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; website (looks rather similar to the &lt;strong&gt;new&lt;/strong&gt; GNER website) &amp;#8211; then ring 08547225111&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;A Brighter Future?&lt;/h3&gt;


	&lt;p&gt;On a more optimistic note, it looks like the new &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; website allows you to change Advance Single tickets on-line up to 5 days before departure. If it works that&amp;#8217;ll be great :-)&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;As is &lt;a href="http://blog.floehopper.org/articles/2007/10/29/changing-gner-advance-single-tickets"&gt;so often&lt;/a&gt; &lt;a href="http://blog.floehopper.org/articles/2007/11/08/changing-gner-advance-single-tickets-reply"&gt;the case&lt;/a&gt;, today I wanted to change the date of some of my &lt;span class="caps"&gt;GNER&lt;/span&gt; Advance Single tickets. I&amp;#8217;ve never written down the phone number of the &lt;a href="http://getsatisfaction.com/gner"&gt;&lt;span class="caps"&gt;GNER&lt;/span&gt;&lt;/a&gt; website support team, so I looked at a couple of the old &lt;span class="caps"&gt;GNER&lt;/span&gt; URLs to see if I could find it.&lt;/p&gt;


	&lt;p&gt;Skip ahead to &lt;a href="#the-nub-of-the-matter"&gt;The Nub of the Matter&lt;/a&gt; if you&amp;#8217;re not very interested in the gory details.&lt;/p&gt;


	&lt;h3&gt;From Pillar to Post&lt;/h3&gt;


&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2166535107"&gt;&lt;img src="http://farm3.static.flickr.com/2301/2166535107_a3109f1bf5.jpg" width="500" height="133" alt="gner-weve-moved" title="gner-weve-moved"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:500px"&gt;www.gner.co.uk - redirects to NXEC website and gives no phone number&lt;/p&gt;&lt;/div&gt;

&lt;div style="" class="flickrplugin"&gt;&lt;a href="http://www.flickr.com/photos/jamesthecat/2167328154"&gt;&lt;img src="http://farm3.static.flickr.com/2357/2167328154_f74a04d868.jpg" width="500" height="332" alt="gnertickets-weve-moved" title="gnertickets-weve-moved"/&gt;&lt;/a&gt;&lt;p class="caption" style="width:500px"&gt;www.gnertickets.co.uk - gives the number 08457225111&lt;/p&gt;&lt;/div&gt;

	&lt;p&gt;So I rang 08457225111. It was the &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; customer support number. I waited on hold for a few minutes and pressed a number of option buttons as is the way of things. Eventually I spoke to a human being and asked whether they could change my tickets. They said they couldn&amp;#8217;t, but that I should ring 08700101127. So I did. This turned out to be the Virgin customer support number. After the obligatory wait and button pushing, I spoke to a human who told me I had been given the wrong number. I was given a new number &amp;#8211; 08457225225 (option #2, followed by option #4).&lt;/p&gt;


	&lt;p&gt;This got me back to &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; and which was decidedly annoying. They then gave me another number (08700101296) which they said was for &amp;#8220;The Train Line&amp;#8221; who apparently used to run the &lt;span class="caps"&gt;GNER&lt;/span&gt; website. However when I got through to them, they denied all knowledge and gave me yet another number &amp;#8211; 08703665990. This finally got me through to &lt;span class="caps"&gt;GNER&lt;/span&gt; &amp;#8211; hooray!&lt;/p&gt;


	&lt;p&gt;I was worried that there would be complications, because the new tickets would have to be issued by &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt;, whereas the old tickets were issued by &lt;a href="http://getsatisfaction.com/gner"&gt;&lt;span class="caps"&gt;GNER&lt;/span&gt;&lt;/a&gt;. But I was pleasantly surprised to be able to change my &lt;span class="caps"&gt;GNER&lt;/span&gt; Advance Single tickets with no more pain than normal (which included giving my credit card details three times &amp;#8211; once for each ticket &amp;#8211; doh!). In fact the rep I spoke to was remarkably efficient.&lt;/p&gt;


	&lt;p&gt;So there goes another pointless hour of my life&amp;#8230;&lt;/p&gt;


	&lt;h3 id="the-nub-of-the-matter"&gt;The Nub of the Matter&lt;/h3&gt;


If you want to change tickets purchased through:
	&lt;ul&gt;
	&lt;li&gt;the &lt;strong&gt;old&lt;/strong&gt; GNER website &amp;#8211; then ring 08703665990&lt;/li&gt;
		&lt;li&gt;the &lt;strong&gt;new&lt;/strong&gt; (but rather transient) &lt;span class="caps"&gt;GNER&lt;/span&gt; website &amp;#8211; then ring 08547225111&lt;/li&gt;
		&lt;li&gt;the &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; website (looks rather similar to the &lt;strong&gt;new&lt;/strong&gt; GNER website) &amp;#8211; then ring 08547225111&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;A Brighter Future?&lt;/h3&gt;


	&lt;p&gt;On a more optimistic note, it looks like the new &lt;a href="http://www.nationalexpresseastcoast.com/"&gt;&lt;span class="caps"&gt;NXEC&lt;/span&gt;&lt;/a&gt; website allows you to change Advance Single tickets on-line up to 5 days before departure. If it works that&amp;#8217;ll be great :-)&lt;/p&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/211354824" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2008/01/04/more-gner-nxec-advance-single-tickets-shenanigans</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:7a475c05-12b4-448c-baaa-a5e5d1854f9b</id>
    <published>2007-11-29T12:17:48+00:00</published>
    <updated>2007-11-29T12:44:57+00:00</updated>
    <title type="html">Mock Object Injection</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/195245633/mock-object-injection" rel="alternate" type="text/html" />
    <category term="ruby" scheme="http://blog.floehopper.org/articles/tag/ruby" />
    <category term="mock" scheme="http://blog.floehopper.org/articles/tag/mock" />
    <category term="object" scheme="http://blog.floehopper.org/articles/tag/object" />
    <category term="dependency" scheme="http://blog.floehopper.org/articles/tag/dependency" />
    <category term="injection" scheme="http://blog.floehopper.org/articles/tag/injection" />
    <category term="collaborator" scheme="http://blog.floehopper.org/articles/tag/collaborator" />
    <category term="testing" scheme="http://blog.floehopper.org/articles/tag/testing" />
    <summary type="html">&lt;p&gt;A few months back, in my &lt;a href="http://blog.floehopper.org/presentations/lrug-mock-objects-2007-07-09/"&gt;Introduction to Mock Objects talk&lt;/a&gt; at &lt;a href="http://lrug.org"&gt;&lt;span class="caps"&gt;LRUG&lt;/span&gt;&lt;/a&gt;, I talked about &amp;#8220;Mock Object Injection&amp;#8221;. At the time I described a number of different ways of replacing a production object with a &lt;a href="http://www.mockobjects.com"&gt;Mock Object&lt;/a&gt; using &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt;. I remember that at &lt;a href="http://lrug.org/meetings/2007/06/20/july-2007-meeting/"&gt;the meeting&lt;/a&gt;, &lt;a href="http://interblah.net/"&gt;James Adam&lt;/a&gt; (who has since joined the team at &lt;a href="http://www.reevoo.com"&gt;Reevoo&lt;/a&gt;) asked me why I didn&amp;#8217;t like the &lt;a href="#any-instance-stub-injection"&gt;Any Instance Stub Injection&lt;/a&gt; technique.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m not sure I gave him a very convincing response and I&amp;#8217;ve been meaning for ages to have a better go at explaining what I think are the pros and cons of each of the techniques I mentioned. Here&amp;#8217;s the list of techniques with the ones I like best at the top. I still haven&amp;#8217;t done a very good job, but I&amp;#8217;d be interested to hear what other people think so that I can try and improve my understanding.&lt;/p&gt;


	&lt;h3 id="constructor-injection"&gt;Constructor Injection&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;ClassUnderTest&lt;/code&gt; allows its dependencies to be passed in as parameters to its constructor. A mock object is passed in as a replacement for the &amp;#8220;real&amp;#8221; collaborator. It may be convenient to specify the production collaborator as a default parameter value.&lt;/p&gt;


	&lt;h4&gt;Advantages&lt;/h4&gt;


	&lt;p&gt;The dependencies of the &lt;code&gt;ClassUnderTest&lt;/code&gt; are explicit.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;Can&amp;#8217;t think of any at the moment.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="comment"&gt;# constructor parameter injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="parameter-injection"&gt;Parameter Injection&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;ClassUnderTest&lt;/code&gt; allows its dependencies to be passed in as parameters to the method under test. A mock object is passed in as a replacement for the &amp;#8220;real&amp;#8221; collaborator. It may be convenient to specify the production collaborator as a default parameter value.&lt;/p&gt;


	&lt;h4&gt;Advantages&lt;/h4&gt;


	&lt;p&gt;The dependencies of the method under test are explicit.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;Can&amp;#8217;t think of any at the moment.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;local_dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="comment"&gt;# use local_dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# method parameter injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="stubbed-new-method-injection"&gt;Stubbed New Method Injection&lt;/h3&gt;


	&lt;p&gt;Use Mocha&amp;#8217;s &lt;a href="http://mocha.rubyforge.org/classes/Object.html#M000003"&gt;Object#stubs&lt;/a&gt; to temporarily replace &lt;code&gt;Collaborator#new&lt;/code&gt; with a stub implementation that returns a mock object.&lt;/p&gt;


	&lt;h4&gt;Advantages&lt;/h4&gt;


	&lt;p&gt;Better than &lt;a href="#any-instance-stub-injection"&gt;Any Instance Stub Injection&lt;/a&gt;, because you can have more control over different instances of &lt;code&gt;Collaborator&lt;/code&gt;.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;Dependencies of the &lt;code&gt;ClassUnderTest&lt;/code&gt; are hidden and not explicit.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="comment"&gt;# stubbed new method injection&lt;/span&gt;
  &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stubs&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:new&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="writer-method-injection"&gt;Writer Method Injection&lt;/h3&gt;


	&lt;p&gt;Use an attribute writer method to replace the &amp;#8220;real&amp;#8221; collaborator with a mock object.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The &lt;code&gt;ClassUnderTest&lt;/code&gt; has to unnecessarily expose a way to modify its internal state. The test is coupled to the implementation of the &lt;code&gt;ClassUnderTest&lt;/code&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="ident"&gt;attr_writer&lt;/span&gt; &lt;span class="symbol"&gt;:dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# writer method injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;collaborator&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="stubbed-private-method-injection"&gt;Stubbed Private Method Injection&lt;/h3&gt;


	&lt;p&gt;Use &lt;em&gt;partial mocking&lt;/em&gt; to temporarily replace a private builder method with a stubbed version of the method.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The test is coupled to the implementation of the &lt;code&gt;ClassUnderTest&lt;/code&gt;. The partial mocking of the &lt;code&gt;instance_under_test&lt;/code&gt; means that the test is not testing a pristine instance of the &lt;code&gt;ClassUnderTest&lt;/code&gt;, but a modified one. It also means that the boundaries between test code and production code are less clear.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="ident"&gt;local_dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;build_collaborator&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
      &lt;span class="comment"&gt;# use local_dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;private&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;build_collaborator&lt;/span&gt;
      &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# stubbed private method injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stubs&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:build_collaborator&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="any-instance-stub-injection"&gt;Any Instance Stub Injection&lt;/h3&gt;


	&lt;p&gt;Use Mocha&amp;#8217;s &lt;a href="http://mocha.rubyforge.org/classes/Class.html#M000001"&gt;Class#any_instance&lt;/a&gt; method to temporarily replace the method on a collaborator with a stub method.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The stubbed method is applied to &lt;strong&gt;all&lt;/strong&gt; instances of the collaborating class. If the &lt;code&gt;instance_under_test&lt;/code&gt; interacts with the stubbed method on more than one instance of the collaborating class, it isn&amp;#8217;t possible to specify different behaviour for the stubbed method on each instance. Even if the &lt;code&gt;instance_under_test&lt;/code&gt; only interacts with the stubbed method on one instance of the collaborating class, the test is specifying more stubbed behaviour than strictly necessary which could lead to false positives.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="ident"&gt;local_dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;local_dependency&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_stuff&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="comment"&gt;# any_instance stub injection&lt;/span&gt;
  &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;any_instance&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stubs&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:do_stuff&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;return&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;something useful&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="instance-variable-set-injection"&gt;Instance Variable Set Injection&lt;/h3&gt;


	&lt;p&gt;Use &lt;a href="http://www.ruby-doc.org/core/classes/Object.html#M000366"&gt;&lt;code&gt;Object#instance_variable_set&lt;/code&gt;&lt;/a&gt; to replace the reference to a collaborator with a mock object.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The test is coupled to the implementation of the &lt;code&gt;ClassUnderTest&lt;/code&gt;. In particular the test is coupled to the supposedly private instance variable. In my opinion, it would be more honest to expose the instance variable by adding an attribute writer and using &lt;a href="#writer-method-injection"&gt;Writer Method Injection&lt;/a&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# instance_variable_set injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variable_set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:@dependency&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary>
    <content type="html">&lt;p&gt;A few months back, in my &lt;a href="http://blog.floehopper.org/presentations/lrug-mock-objects-2007-07-09/"&gt;Introduction to Mock Objects talk&lt;/a&gt; at &lt;a href="http://lrug.org"&gt;&lt;span class="caps"&gt;LRUG&lt;/span&gt;&lt;/a&gt;, I talked about &amp;#8220;Mock Object Injection&amp;#8221;. At the time I described a number of different ways of replacing a production object with a &lt;a href="http://www.mockobjects.com"&gt;Mock Object&lt;/a&gt; using &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt;. I remember that at &lt;a href="http://lrug.org/meetings/2007/06/20/july-2007-meeting/"&gt;the meeting&lt;/a&gt;, &lt;a href="http://interblah.net/"&gt;James Adam&lt;/a&gt; (who has since joined the team at &lt;a href="http://www.reevoo.com"&gt;Reevoo&lt;/a&gt;) asked me why I didn&amp;#8217;t like the &lt;a href="#any-instance-stub-injection"&gt;Any Instance Stub Injection&lt;/a&gt; technique.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m not sure I gave him a very convincing response and I&amp;#8217;ve been meaning for ages to have a better go at explaining what I think are the pros and cons of each of the techniques I mentioned. Here&amp;#8217;s the list of techniques with the ones I like best at the top. I still haven&amp;#8217;t done a very good job, but I&amp;#8217;d be interested to hear what other people think so that I can try and improve my understanding.&lt;/p&gt;


	&lt;h3 id="constructor-injection"&gt;Constructor Injection&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;ClassUnderTest&lt;/code&gt; allows its dependencies to be passed in as parameters to its constructor. A mock object is passed in as a replacement for the &amp;#8220;real&amp;#8221; collaborator. It may be convenient to specify the production collaborator as a default parameter value.&lt;/p&gt;


	&lt;h4&gt;Advantages&lt;/h4&gt;


	&lt;p&gt;The dependencies of the &lt;code&gt;ClassUnderTest&lt;/code&gt; are explicit.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;Can&amp;#8217;t think of any at the moment.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="comment"&gt;# constructor parameter injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="parameter-injection"&gt;Parameter Injection&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;ClassUnderTest&lt;/code&gt; allows its dependencies to be passed in as parameters to the method under test. A mock object is passed in as a replacement for the &amp;#8220;real&amp;#8221; collaborator. It may be convenient to specify the production collaborator as a default parameter value.&lt;/p&gt;


	&lt;h4&gt;Advantages&lt;/h4&gt;


	&lt;p&gt;The dependencies of the method under test are explicit.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;Can&amp;#8217;t think of any at the moment.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;local_dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="comment"&gt;# use local_dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# method parameter injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="stubbed-new-method-injection"&gt;Stubbed New Method Injection&lt;/h3&gt;


	&lt;p&gt;Use Mocha&amp;#8217;s &lt;a href="http://mocha.rubyforge.org/classes/Object.html#M000003"&gt;Object#stubs&lt;/a&gt; to temporarily replace &lt;code&gt;Collaborator#new&lt;/code&gt; with a stub implementation that returns a mock object.&lt;/p&gt;


	&lt;h4&gt;Advantages&lt;/h4&gt;


	&lt;p&gt;Better than &lt;a href="#any-instance-stub-injection"&gt;Any Instance Stub Injection&lt;/a&gt;, because you can have more control over different instances of &lt;code&gt;Collaborator&lt;/code&gt;.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;Dependencies of the &lt;code&gt;ClassUnderTest&lt;/code&gt; are hidden and not explicit.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="comment"&gt;# stubbed new method injection&lt;/span&gt;
  &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stubs&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:new&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="writer-method-injection"&gt;Writer Method Injection&lt;/h3&gt;


	&lt;p&gt;Use an attribute writer method to replace the &amp;#8220;real&amp;#8221; collaborator with a mock object.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The &lt;code&gt;ClassUnderTest&lt;/code&gt; has to unnecessarily expose a way to modify its internal state. The test is coupled to the implementation of the &lt;code&gt;ClassUnderTest&lt;/code&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="ident"&gt;attr_writer&lt;/span&gt; &lt;span class="symbol"&gt;:dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# writer method injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;collaborator&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="stubbed-private-method-injection"&gt;Stubbed Private Method Injection&lt;/h3&gt;


	&lt;p&gt;Use &lt;em&gt;partial mocking&lt;/em&gt; to temporarily replace a private builder method with a stubbed version of the method.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The test is coupled to the implementation of the &lt;code&gt;ClassUnderTest&lt;/code&gt;. The partial mocking of the &lt;code&gt;instance_under_test&lt;/code&gt; means that the test is not testing a pristine instance of the &lt;code&gt;ClassUnderTest&lt;/code&gt;, but a modified one. It also means that the boundaries between test code and production code are less clear.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="ident"&gt;local_dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;build_collaborator&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
      &lt;span class="comment"&gt;# use local_dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;private&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;build_collaborator&lt;/span&gt;
      &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# stubbed private method injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stubs&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:build_collaborator&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;returns&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="any-instance-stub-injection"&gt;Any Instance Stub Injection&lt;/h3&gt;


	&lt;p&gt;Use Mocha&amp;#8217;s &lt;a href="http://mocha.rubyforge.org/classes/Class.html#M000001"&gt;Class#any_instance&lt;/a&gt; method to temporarily replace the method on a collaborator with a stub method.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The stubbed method is applied to &lt;strong&gt;all&lt;/strong&gt; instances of the collaborating class. If the &lt;code&gt;instance_under_test&lt;/code&gt; interacts with the stubbed method on more than one instance of the collaborating class, it isn&amp;#8217;t possible to specify different behaviour for the stubbed method on each instance. Even if the &lt;code&gt;instance_under_test&lt;/code&gt; only interacts with the stubbed method on one instance of the collaborating class, the test is specifying more stubbed behaviour than strictly necessary which could lead to false positives.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="ident"&gt;local_dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
      &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;local_dependency&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_stuff&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="comment"&gt;# any_instance stub injection&lt;/span&gt;
  &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;any_instance&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;stubs&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:do_stuff&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;return&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;something useful&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3 id="instance-variable-set-injection"&gt;Instance Variable Set Injection&lt;/h3&gt;


	&lt;p&gt;Use &lt;a href="http://www.ruby-doc.org/core/classes/Object.html#M000366"&gt;&lt;code&gt;Object#instance_variable_set&lt;/code&gt;&lt;/a&gt; to replace the reference to a collaborator with a mock object.&lt;/p&gt;


	&lt;h4&gt;Disadvantages&lt;/h4&gt;


	&lt;p&gt;The test is coupled to the implementation of the &lt;code&gt;ClassUnderTest&lt;/code&gt;. In particular the test is coupled to the supposedly private instance variable. In my opinion, it would be more honest to expose the instance variable by adding an attribute writer and using &lt;a href="#writer-method-injection"&gt;Writer Method Injection&lt;/a&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ClassUnderTest&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
      &lt;span class="attribute"&gt;@dependency&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Collaborator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_something&lt;/span&gt;
      &lt;span class="comment"&gt;# use @dependency&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;collaborator&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ClassUnderTest&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
  &lt;span class="comment"&gt;# instance_variable_set injection&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_variable_set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:@dependency&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;collaborator&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;instance_under_test&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;do_something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/195245633" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2007/11/29/mock-object-injection</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:74aff615-26f8-4733-b5a3-c78ea0ce71ce</id>
    <published>2007-11-08T20:02:18+00:00</published>
    <updated>2007-11-08T20:02:18+00:00</updated>
    <title type="html">Changing GNER Advance Single tickets (reply)</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/195245634/changing-gner-advance-single-tickets-reply" rel="alternate" type="text/html" />
    <category term="gner" scheme="http://blog.floehopper.org/articles/tag/gner" />
    <category term="advance" scheme="http://blog.floehopper.org/articles/tag/advance" />
    <category term="single" scheme="http://blog.floehopper.org/articles/tag/single" />
    <category term="ticket" scheme="http://blog.floehopper.org/articles/tag/ticket" />
    <category term="reply" scheme="http://blog.floehopper.org/articles/tag/reply" />
    <category term="customer" scheme="http://blog.floehopper.org/articles/tag/customer" />
    <category term="service" scheme="http://blog.floehopper.org/articles/tag/service" />
    <category term="satisfaction" scheme="http://blog.floehopper.org/articles/tag/satisfaction" />
    <summary type="html">&lt;p&gt;I finally heard back to my &lt;a href="http://blog.floehopper.org/articles/2007/10/29/changing-gner-advance-single-tickets"&gt;complaint&lt;/a&gt; from &lt;span class="caps"&gt;GNER&lt;/span&gt; Customer Service yesterday (7th Nov). Until then I had not even had an acknowledgment (automated or not) that they&amp;#8217;d received my email. In their response, they acknowledge that it is possible to change tickets purchased online at a ticket office (although you may lose any &amp;#8220;web discount&amp;#8221;).&lt;/p&gt;


	&lt;p&gt;There are some slightly woolly words in the middle, but I&amp;#8217;m pleased they do have the good grace to explicitly apologise for the fact I was &amp;#8220;wrongly advised&amp;#8221; by the Durham Travel Centre.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m pleased to have had a response and it&amp;#8217;s reassuring to hear that they are taking action to improve the situation. I&amp;#8217;m surprised how much better I feel to have had a response.&lt;/p&gt;


	&lt;p&gt;For completeness, I&amp;#8217;ve &lt;a href="http://getsatisfaction.com/gner/topics/changing_advance_single_tickets_that_were_purchased_on_line"&gt;posted the response&lt;/a&gt; on &lt;a href="http://getsatisfaction.com/"&gt;getsatisfaction.com&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the full text of their response with employee names removed&amp;#8230;&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Mr Mead,&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Thank you for your email.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;When making an alteration to an online booking at the station you will not receive the web discount. The web discount, is only applicable to bookings done over the internet, from beginning to end.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;If you wish to make an alteration to your online booking, you can do this at a &lt;span class="caps"&gt;GNER&lt;/span&gt; station, however, you do need to take the full ticket into the station with you. When making an alteration to an online booking at the station, you will loose your online discount, because this ticket is not being booked online.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Our staff usually do an excellent job in meeting the needs of our passengers but I know that there are occasions when incidents occur which cause dissatisfaction. We ask our staff to uphold company policies wherever practical in the interest of fairness and consistency. Unfortunately, this does mean that the ability of the staff to exercise discretion and waive certain policies is very limited.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;I am concerned that you were wrongly advised that online tickets could not be altered at the station, this was incorrect and for this I apologise.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;I will of course forward your comments to the manager responsible for Mr X, who can address this matter directly with him.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;If you have any further questions regarding ghtis matter, please contact me again.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Kind Regards&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Customer Relations&lt;/p&gt;
	&lt;/blockquote&gt;</summary>
    <content type="html">&lt;p&gt;I finally heard back to my &lt;a href="http://blog.floehopper.org/articles/2007/10/29/changing-gner-advance-single-tickets"&gt;complaint&lt;/a&gt; from &lt;span class="caps"&gt;GNER&lt;/span&gt; Customer Service yesterday (7th Nov). Until then I had not even had an acknowledgment (automated or not) that they&amp;#8217;d received my email. In their response, they acknowledge that it is possible to change tickets purchased online at a ticket office (although you may lose any &amp;#8220;web discount&amp;#8221;).&lt;/p&gt;


	&lt;p&gt;There are some slightly woolly words in the middle, but I&amp;#8217;m pleased they do have the good grace to explicitly apologise for the fact I was &amp;#8220;wrongly advised&amp;#8221; by the Durham Travel Centre.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m pleased to have had a response and it&amp;#8217;s reassuring to hear that they are taking action to improve the situation. I&amp;#8217;m surprised how much better I feel to have had a response.&lt;/p&gt;


	&lt;p&gt;For completeness, I&amp;#8217;ve &lt;a href="http://getsatisfaction.com/gner/topics/changing_advance_single_tickets_that_were_purchased_on_line"&gt;posted the response&lt;/a&gt; on &lt;a href="http://getsatisfaction.com/"&gt;getsatisfaction.com&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the full text of their response with employee names removed&amp;#8230;&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Mr Mead,&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Thank you for your email.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;When making an alteration to an online booking at the station you will not receive the web discount. The web discount, is only applicable to bookings done over the internet, from beginning to end.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;If you wish to make an alteration to your online booking, you can do this at a &lt;span class="caps"&gt;GNER&lt;/span&gt; station, however, you do need to take the full ticket into the station with you. When making an alteration to an online booking at the station, you will loose your online discount, because this ticket is not being booked online.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Our staff usually do an excellent job in meeting the needs of our passengers but I know that there are occasions when incidents occur which cause dissatisfaction. We ask our staff to uphold company policies wherever practical in the interest of fairness and consistency. Unfortunately, this does mean that the ability of the staff to exercise discretion and waive certain policies is very limited.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;I am concerned that you were wrongly advised that online tickets could not be altered at the station, this was incorrect and for this I apologise.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;I will of course forward your comments to the manager responsible for Mr X, who can address this matter directly with him.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;If you have any further questions regarding ghtis matter, please contact me again.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Kind Regards&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Customer Relations&lt;/p&gt;
	&lt;/blockquote&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/195245634" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2007/11/08/changing-gner-advance-single-tickets-reply</feedburner:origLink></entry>
  <entry>
    <author>
      <name>James Mead</name>
    </author>
    <id>urn:uuid:0e4ff1dd-c71d-4cb7-99ff-5b5786b3a595</id>
    <published>2007-11-07T23:37:00+00:00</published>
    <updated>2007-11-08T13:51:13+00:00</updated>
    <title type="html">Implementation Patterns</title>
    <link href="http://feeds.floehopper.org/~r/floehopper-blog/~3/195245635/implementation-patterns" rel="alternate" type="text/html" />
    <category term="amazon" scheme="http://blog.floehopper.org/articles/tag/amazon" />
    <category term="implement" scheme="http://blog.floehopper.org/articles/tag/implement" />
    <category term="pattern" scheme="http://blog.floehopper.org/articles/tag/pattern" />
    <category term="beck" scheme="http://blog.floehopper.org/articles/tag/beck" />
    <category term="smalltalk" scheme="http://blog.floehopper.org/articles/tag/smalltalk" />
    <summary type="html">&lt;p&gt;I&amp;#8217;m looking forward to reading Kent Beck&amp;#8217;s new book &lt;a href="http://www.amazon.co.uk/Implementation-Patterns-Kent-Beck/dp/0321413091"&gt;Implementation Patterns&lt;/a&gt;  which has been &lt;a href="http://www.infoq.com/articles/implementations-patterns-br"&gt;reviewed on InfoQ&lt;/a&gt;. I&amp;#8217;ve had it on pre-order at Amazon and it&amp;#8217;s just been dispatched. I always meant to read his Smalltalk equivalent &lt;a href="http://www.amazon.co.uk/Smalltalk-Best-Practice-Patterns-Kent/dp/013476904X"&gt;Smalltalk Best Practice Patterns&lt;/a&gt;, but never quite got round to it.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I&amp;#8217;m looking forward to reading Kent Beck&amp;#8217;s new book &lt;a href="http://www.amazon.co.uk/Implementation-Patterns-Kent-Beck/dp/0321413091"&gt;Implementation Patterns&lt;/a&gt;  which has been &lt;a href="http://www.infoq.com/articles/implementations-patterns-br"&gt;reviewed on InfoQ&lt;/a&gt;. I&amp;#8217;ve had it on pre-order at Amazon and it&amp;#8217;s just been dispatched. I always meant to read his Smalltalk equivalent &lt;a href="http://www.amazon.co.uk/Smalltalk-Best-Practice-Patterns-Kent/dp/013476904X"&gt;Smalltalk Best Practice Patterns&lt;/a&gt;, but never quite got round to it.&lt;/p&gt;&lt;img src="http://feeds.floehopper.org/~r/floehopper-blog/~4/195245635" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.floehopper.org/articles/2007/11/07/implementation-patterns</feedburner:origLink></entry>
</feed>
