<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.2.2" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Denis Hennessy</title>
	<link>http://hennessynet.com</link>
	<description>Musings on Software Development</description>
	<pubDate>Thu, 08 May 2008 11:12:46 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2.2</generator>
	<language>en</language>
			<item>
		<title>Programming competition time again</title>
		<link>http://hennessynet.com/index.php/2008/05/08/programming-competition-time-again/</link>
		<comments>http://hennessynet.com/index.php/2008/05/08/programming-competition-time-again/#comments</comments>
		<pubDate>Thu, 08 May 2008 11:09:18 +0000</pubDate>
		<dc:creator>denis</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://hennessynet.com/index.php/2008/05/08/programming-competition-time-again/</guid>
		<description><![CDATA[The dates have just appeared for this years ICFP contest:
July 11, 2008 &#8212; July 14, 2008
The weekend is now blocked out in my calendar and family, friends and pets warned to expect no care and attention. I&#8217;m hoping to organise a bigger team this year (2-3 people from last year was too small) - I [...]]]></description>
			<content:encoded><![CDATA[<p>The dates have just appeared for this years ICFP contest:</p>
<p>July 11, 2008 &#8212; July 14, 2008</p>
<p>The weekend is now blocked out in my calendar and family, friends and pets warned to expect no care and attention. I&#8217;m hoping to organise a bigger team this year (2-3 people from last year was too small) - I think 5-6 might be the optimum size.</p>
<p>Here are some past contests:</p>
<ul>
<li><a href="http://www.icfpcontest.org/">2007, organized by Utrecht University</a></li>
<li><a href="http://www.boundvariable.org/">2006, organized by CMU</a></li>
<li><a href="http://icfpc.plt-scheme.org/">2005, organized by PLT and friends</a></li>
<li><a href="http://www.cis.upenn.edu/proj/plclub/contest/">2004, organized by Penn</a></li>
<li><a href="http://www.dtek.chalmers.se/groups/icfpcontest">2003, organized by Chalmers</a></li>
<li><a href="http://web.cecs.pdx.edu/%7Esheard/2002IcfpContest/">2002, organized by OGI</a></li>
<li><a href="http://cristal.inria.fr/ICFP2001/prog-contest/">2001, organized by INRIA Rocquencourt</a></li>
<li><a href="http://www.cs.cornell.edu/icfp/">2000, organized by Cornell and Bell Labs</a></li>
<li><a href="http://www.eecs.harvard.edu/nr/icfp/problem.html">1999, organized by Harvard and Virginia</a></li>
<li><a href="http://www.ai.mit.edu/extra/icfp-contest/">1998, organized by Universite de Montreal and<br />
      MIT</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://hennessynet.com/index.php/2008/05/08/programming-competition-time-again/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Unit testing Spring/Hibernate code using JMock</title>
		<link>http://hennessynet.com/index.php/2008/02/27/unit-testing-springhibernate-code-using-jmock/</link>
		<comments>http://hennessynet.com/index.php/2008/02/27/unit-testing-springhibernate-code-using-jmock/#comments</comments>
		<pubDate>Wed, 27 Feb 2008 20:51:29 +0000</pubDate>
		<dc:creator>denis</dc:creator>
		
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://hennessynet.com/index.php/2008/02/27/unit-testing-springhibernate-code-using-jmock/</guid>
		<description><![CDATA[Unit testing a simple Java class like, say, a four-function calculator is trivially easy using JUnit. However, things get a lot harder when you&#8217;re using complex support frameworks like Spring or Hibernate.  Here are some guidelines for using JMock to help isolate the framework and focus on the code you&#8217;re testing.
Before you start, take [...]]]></description>
			<content:encoded><![CDATA[<p>Unit testing a simple Java class like, say, a four-function calculator is trivially easy using JUnit. However, things get a lot harder when you&#8217;re using complex support frameworks like Spring or Hibernate.  Here are some guidelines for using JMock to help isolate the framework and focus on the code you&#8217;re testing.</p>
<p>Before you start, take a minute to consider whether it&#8217;s truly a unit test you&#8217;re looking for. The key question is whether your code is really independent from the environment, or if it depends on some clever capability of the framework or database. For example, suppose it generated some complex SQL and then used the results of that SQL; you should consider whether your tests might need to interact with a real database to be sure that your code is correct. If that&#8217;s the case, then you probably shouldn&#8217;t be using mocks.</p>
<p>Mocking objects in java is actually quite hard to do (much harder than Ruby or Smalltalk) but JMock helps a lot. JMock (<a href="http://www.jmock.org/">http://www.jmock.org/</a>) has improved hugely in version 2 - it&#8217;s practically a rewrite from version 1. Also, I&#8217;m going to use JUnit 4 which allows us to use annotations.</p>
<p>Let&#8217;s assume we&#8217;ve just written Shipper class with a method that computes the weight of a shipment by adding the weights of the individual components and the weight of a standard shipping box. There&#8217;s a catalog service that can retrieve the weight of a component and a config service that stores the standard shipping box weight. Spring is used to wire together the services and Hibernate is used to persist the data. Here&#8217;s what our class might look like (the database locking is just to make it interesting):</p>
<pre class="java" name="code">
package com.sample;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.LockMode;
import org.springframework.orm.hibernate3.SessionFactoryUtils;

public class Shipper {
    Config config;
    Catalog catalog;
    SessionFactory sessionFactory;

    public void setConfig(Config config) {
        this.config = config;
    }

    public void setCatalog(Catalog catalog) {
        this.catalog = catalog;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void updateTotalWeight(Shipment shipment, String[] ids) {
        Session session = SessionFactoryUtils.getSession(sessionFactory, true);
        session.refresh(shipment, LockMode.UPGRADE_NOWAIT);

        int weight = config.getStandardShippingWeight();
        if (ids != null) {
            for (String id : ids) {
                weight += catalog.getWeight(id);
            }
        }

        shipment.setWeight(weight);
    }
}
</pre>
<p>Now let&#8217;s look at the test code for this class (I&#8217;ve deleted most comments from both files to make them easier to follow). Our objective in the test is to verify the &#8216;happy route&#8217; through the method, as well as the edge cases with a null or empty list:</p>
<pre class="java" name="code">
package com.sample;

import static org.junit.Assert.assertEquals;
import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.Mockery;
import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser;
import org.hibernate.SessionFactory;
import org.hibernate.Session;

@RunWith(JMock.class)
public class ShipperTestCase {
    Mockery context;
    Shipper shipper;
    Catalog catalog;
    Config config;
    SessionFactory sessionFactory;
    Session session;

    @Before
    public void prepareMocks() {
        context = new JUnit4Mockery() {
            {
                // Enable mocks of concrete classes
                setImposteriser(ClassImposteriser.INSTANCE);
            }
        };
        catalog = context.mock(Catalog.class);
        config = context.mock(Config.class);
        sessionFactory = context.mock(SessionFactory.class);
        session = context.mock(Session.class);

        // Create our test object and wire up mock services to it

        shipper = new Shipper();
        shipper.setCatalog(catalog);
        shipper.setConfig(config);
        shipper.setSessionFactory(sessionFactory);
    }

    @Test
    public void emptyOrNullList() {
        Shipment shipment = new Shipment();

        // Set up the expected behaviour in the support services
        context.checking(new Expectations() {
            {
                allowing(sessionFactory).openSession(); will(returnValue(session));
                allowing(session).getSessionFactory(); will(returnValue(sessionFactory));
                ignoring(session);

                // Set required expectations for test to pass
                atLeast(1).of(config).getStandardShippingWeight(); will(returnValue(8));
            }

        });
        shipper.updateTotalWeight(shipment, null);
        assertEquals(8, shipment.getWeight());
        shipment.setWeight(0);
        shipper.updateTotalWeight(shipment, new String[0]);
        assertEquals(8, shipment.getWeight());
    }

    @Test
    public void sampleList() {
        Shipment shipment = new Shipment();

        // Set up the expected behaviour in the support services
        context.checking(new Expectations() {
            {
                allowing(sessionFactory).openSession(); will(returnValue(session));
                allowing(session).getSessionFactory(); will(returnValue(sessionFactory));
                ignoring(session);

                // Set required expectations for test to pass
                atLeast(1).of(config).getStandardShippingWeight(); will(returnValue(4));
                atLeast(1).of(catalog).getWeight("a"); will(returnValue(1));
                atLeast(1).of(catalog).getWeight("b"); will(returnValue(2));
                atLeast(1).of(catalog).getWeight("c"); will(returnValue(4));
            }

        });
        shipper.updateTotalWeight(shipment, new String[] { "a", "b", "c"});
        assertEquals(15, shipment.getWeight());
    }
}
</pre>
<p>Let&#8217;s look at a few interesting parts of the test code:</p>
<pre class="java" name="code">
@RunWith(JMock.class)
public class ShipperTestCase {
</pre>
<p>This causes JUnit to use the runner from JMock, instead of its built-it one.</p>
<pre class="java" name="code">
    @Before
    public void prepareMocks() {
        context = new JUnit4Mockery() {
            {
                setImposteriser(ClassImposteriser.INSTANCE);    // Enable mocks of concrete classes
            }
        };
        catalog = context.mock(Catalog.class);
        config = context.mock(Config.class);
        sessionFactory = context.mock(SessionFactory.class);
        session = context.mock(Session.class);

        // Create our test object and wire up mock services to it

        shipper = new Shipper();
        shipper.setCatalog(catalog);
        shipper.setConfig(config);
        shipper.setSessionFactory(sessionFactory);
    }
</pre>
<p>This method runs before each of the test cases. It&#8217;s (hopefully) very straightforward - it creates mock objects for each of the external services that our class relies on, and then creates an object to test with those mocks wired to it.</p>
<pre class="java" name="code">
        // Set up the expected behaviour in the support services
        context.checking(new Expectations() {
            {
                allowing(sessionFactory).openSession(); will(returnValue(session));
                allowing(session).getSessionFactory(); will(returnValue(sessionFactory));
                ignoring(session);

                // Set required expectations for test to pass
                atLeast(1).of(config).getStandardShippingWeight(); will(returnValue(4));
                atLeast(1).of(catalog).getWeight("a"); will(returnValue(1));
                atLeast(1).of(catalog).getWeight("b"); will(returnValue(2));
                atLeast(1).of(catalog).getWeight("c"); will(returnValue(4));
            }

        });
</pre>
<p>This block sets the behaviour we want from our mocks. Notice that we can specify different behaviour based on different parameters to a method. The ignoring(session) line indicates that all other methods of session should simply return a default value.</p>
<pre class="java" name="code">
        shipper.updateTotalWeight(shipment, new String[] { "a", "b", "c"});
        assertEquals(15, shipment.getWeight());
</pre>
<p>Finally, we call our test object and verify the results.</p>
<p>When writing expectations, it&#8217;s worth making sure you only set constraints (like the atLeast(1) line) where a mock method MUST be called or you consider the test as failed. If you make the constraints too tight, then your tests can get brittle and can fail when you change the implementation, even if that change hasn&#8217;t broken the functionality. For example, if I&#8217;d used exactly(1) instead of atLeast(1), the test would still pass but would be less resilient to implementation changes.</p>
]]></content:encoded>
			<wfw:commentRss>http://hennessynet.com/index.php/2008/02/27/unit-testing-springhibernate-code-using-jmock/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Protecting email addresses on web pages</title>
		<link>http://hennessynet.com/index.php/2008/02/23/protecting-email-addresses-on-web-pages/</link>
		<comments>http://hennessynet.com/index.php/2008/02/23/protecting-email-addresses-on-web-pages/#comments</comments>
		<pubDate>Sat, 23 Feb 2008 14:56:18 +0000</pubDate>
		<dc:creator>denis</dc:creator>
		
		<category><![CDATA[hosting]]></category>

		<guid isPermaLink="false">http://hennessynet.com/index.php/2008/02/23/protecting-email-addresses-on-web-pages/</guid>
		<description><![CDATA[I was adding my email address to peerassembly.com and used a little javascript snippit to hide the email address from simple (read: stupid) email harvester bots. It&#8217;s so short, it hardly warrants a post but maybe someone will find it the next time they&#8217;re putting a contact email address on a web page and save [...]]]></description>
			<content:encoded><![CDATA[<p>I was adding my email address to <a href="http://peerassembly.com">peerassembly.com</a> and used a little javascript snippit to hide the email address from simple (read: stupid) email harvester bots. It&#8217;s so short, it hardly warrants a post but maybe someone will find it the next time they&#8217;re putting a contact email address on a web page and save themselves a ton of spam!</p>
<p>If you don&#8217;t have it already, add prototype.js to your page:</p>
<pre>
  &lt;script src="javascripts/prototype.js" type="text/javascript" charset="utf-8">&lt;/script>
</pre>
<p>At the place in your page where you put your email address, replace it with:</p>
<pre>
&lt;span id="email">info&lt;/span>
</pre>
<p>Then, add this to your page:</p>
<pre>
  &lt;script type="text/javascript">
  var a = "info" + "&amp;#64;" + "peerassembly.com";
  $('email').update('&lt;a href="mailto:'+a+'">'+a+'&lt;/a>');
  &lt;/script>
</pre>
<p>That&#8217;s it - when the javascript executes, it will insert the email link in your page.</p>
]]></content:encoded>
			<wfw:commentRss>http://hennessynet.com/index.php/2008/02/23/protecting-email-addresses-on-web-pages/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using capistrano for static sites</title>
		<link>http://hennessynet.com/index.php/2008/02/14/using-capistrano-for-static-sites/</link>
		<comments>http://hennessynet.com/index.php/2008/02/14/using-capistrano-for-static-sites/#comments</comments>
		<pubDate>Thu, 14 Feb 2008 21:18:08 +0000</pubDate>
		<dc:creator>denis</dc:creator>
		
		<category><![CDATA[hosting]]></category>

		<guid isPermaLink="false">http://hennessynet.com/index.php/2008/02/14/using-capistrano-for-static-sites/</guid>
		<description><![CDATA[I&#8217;ve been using capistrano for rails deployment for a while. I thought I&#8217;d see how useful it was for managing some static sites - it turned out to be really useful. Here&#8217;s how to do it:
First, create the project in subversion and check it out. I really like the idea of everything being in source [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using capistrano for rails deployment for a while. I thought I&#8217;d see how useful it was for managing some static sites - it turned out to be really useful. Here&#8217;s how to do it:</p>
<p>First, create the project in subversion and check it out. I really like the idea of <strong><em>everything</em></strong> being in source control. My normal process for updating a site is:</p>
<ul>
<li>check out site files</li>
<li>make changes</li>
<li>review locally</li>
<li>check them in</li>
<li>publish updated site</li>
</ul>
<p>Capistrano helps with the last step - to publish your updated site, you simply use:</p>
<pre>$ cap deploy:update</pre>
<p>In this example, my subversion repository is at dev.work.com/svn the site is mysite.com and the server is located at bighost.com</p>
<pre>$ svn mkdir http://dev.work.com/svn/mysite
$ svn co http://dev.work.com/svn/mysite
$ cd mysite
$ mkdir -p config public public/images public/stylesheets public/javascripts
$ capify .
[add] writing `./Capfile'
[add] writing `./config/deploy.rb'
[done] capified!</pre>
<p>If you already have content for the site, copy it into the ./public directory tree. Otherwise, create the content in place.</p>
<p>Edit config/deploy.rb as follows
<pre name="code" class="ruby">set :application, "mysite"
set :repository,  "http://dev.work.com/svn/mysite"
set :deploy_via, :copy

set :deploy_to, "/home/denis/#{application}"

role :app, "bighost.com"
role :web, "bighost.com"
role :db,  "bighost.com", :primary =&gt; true</pre>
<p>Check all of these into subversion and create the server-side directories with:</p>
<pre>$ svn add *
$ svn ci
$ cap deploy:setup</pre>
<p>Note that in this example, the web site is served from /home/denis/mysite/current/public. Here&#8217;s the apache config file (to be installed in /etc/apache2/sites-available) to make that work:</p>
<pre name="code" class="xml">&lt;VirtualHost *&gt;
        ServerAdmin denis@hennessynet.com
        ServerName mysite.com
	    ServerAlias www. mysite.com
        DocumentRoot /home/denis/mysite/current/public
        &lt;Directory /home/denis/mysite/current/public&gt;
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
        &lt;/Directory&gt;

        ErrorLog /var/log/apache2/error. mysite.log
        CustomLog /var/log/apache2/access. mysite.log combined
&lt;/VirtualHost&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://hennessynet.com/index.php/2008/02/14/using-capistrano-for-static-sites/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Wil Shipley on Adwords, Indie Mac development and more</title>
		<link>http://hennessynet.com/index.php/2008/02/10/wil-shipley-on-adwords-indie-mac-development-and-more/</link>
		<comments>http://hennessynet.com/index.php/2008/02/10/wil-shipley-on-adwords-indie-mac-development-and-more/#comments</comments>
		<pubDate>Sun, 10 Feb 2008 14:42:03 +0000</pubDate>
		<dc:creator>denis</dc:creator>
		
		<category><![CDATA[mac]]></category>

		<guid isPermaLink="false">http://hennessynet.com/index.php/2008/02/10/wil-shipley-on-adwords-indie-mac-development-and-more/</guid>
		<description><![CDATA[I just watched Wil Shipley&#8217;s presentation from C4[1] (video).  The topic is generally about how to best use hype to promote your application (it was in front of an audience of Mac Indie developers). Besides being thoroughly enjoyable to watch, it contained quite a number of interesting tidbits on Google adwords, beta and upgrade [...]]]></description>
			<content:encoded><![CDATA[<p>I just watched Wil Shipley&#8217;s presentation from C4[1] (<a href="http://www.viddler.com/explore/rentzsch/videos/4/" target="_blank">video</a>).  The topic is generally about how to best use hype to promote your application (it was in front of an audience of Mac Indie developers). Besides being thoroughly enjoyable to watch, it contained quite a number of interesting tidbits on Google adwords, beta and upgrade policies, &#8230; </p>
<p>Recommended.  </p>
]]></content:encoded>
			<wfw:commentRss>http://hennessynet.com/index.php/2008/02/10/wil-shipley-on-adwords-indie-mac-development-and-more/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Installing MacPorts and MySQL on Leopard</title>
		<link>http://hennessynet.com/index.php/2008/01/15/installing-macports-and-mysql-on-leopard/</link>
		<comments>http://hennessynet.com/index.php/2008/01/15/installing-macports-and-mysql-on-leopard/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 17:58:26 +0000</pubDate>
		<dc:creator>denis</dc:creator>
		
		<category><![CDATA[mac]]></category>

		<guid isPermaLink="false">http://hennessynet.com/index.php/2008/01/15/installing-macports-and-mysql-on-leopard/</guid>
		<description><![CDATA[I recently had to re-install a development environment on a Mac Pro so I kept track of the steps as I went. Here&#8217;s the simplest way to get MacPorts and MySQL installed on Leopard.

Install XCode 3.0 from Leopard Install Disk 2
Download MacPorts installer from http://www.macports.org/install.php and run.

Then, add the following to ~/.bash_profile (and then restart [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had to re-install a development environment on a Mac Pro so I kept track of the steps as I went. Here&#8217;s the simplest way to get MacPorts and MySQL installed on Leopard.</p>
<ol>
<li>Install XCode 3.0 from Leopard Install Disk 2</li>
<li>Download MacPorts installer from http://www.macports.org/install.php and run.</li>
</ol>
<p>Then, add the following to ~/.bash_profile (and then restart your Terminal):</p>
<pre name="code" class="ruby">
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
export MANPATH=/opt/local/share/man:$MANPATH
export ARCHFLAGS="-arch i386"
bind 'set completion-ignore-case on'
</pre>
<p>That last line is not strictly needed but I like to be able to tab through directory names without caring about the capitalisation. Finally run:</p>
<pre>
$ sudo port -v selfupdate
</pre>
<p>OK, that&#8217;s MacPorts out of the way, on to MySQL:</p>
<pre>
$ sudo port install mysql5 +server
$ sudo -u mysql mysql_install_db5
$ cd /opt/local
$ sudo /opt/local/lib/mysql5/bin/mysqld_safe
</pre>
<p>Add the following as /opt/local/etc/mysql5/my.cnf:</p>
<pre>
[mysqld_safe]
socket=/tmp/mysql.sock
</pre>
<p>Lastly, try it out (and set it to start on reboot) with:</p>
<pre>
$ sudo /opt/local/lib/mysql5/bin/mysqld_safe
$ sudo launchctl load -w /Library/LaunchDaemons/org.macports.mysql5.plist
$ sudo ln -s /tmp/mysql.sock /opt/local/var/run/mysql5/mysqld.sock
</pre>
<p>If I&#8217;ve missed anything, let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://hennessynet.com/index.php/2008/01/15/installing-macports-and-mysql-on-leopard/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
