03 December 2009

Better testing, part 2 – Language in testing

Naming is one of the most important parts of programming. The same is true of testing. A badly named test is hard to understand where as a well named test can be read and understood in an instant. Not only that, good test naming can lead to a better understanding of the problem and so a better solution and a more thoroughly tested implementation.

Should

A great technic for better test naming is by adding “should” to your testing vocabulary.

Let’s take for example a function that give you all the distinct items that have been added to the basket.

 1 
 2 class BasketTest < Test::Unit::TestCase
 3 
 4   def setup
 5     @product1 = Product.new(:name => 'Cheese')
 6     @product2 = Product.new(:name => 'Crisps')
 7     @product3 = Product.new(:name => 'Soap')
 8   end
 9 
10   # Bad testing
11   def test_individual_items
12     b = Basket.new
13     b.add(@product1)
14     b.add(@product3)
15     b.add(@product1)
16 
17     assert_equal 2, b.individual_items.size
18   end
19 
20   # Better
21   def test_should_only_return_distinct_products_that_have_been_added
22     b = Basket.new
23     b.add(@product1)
24     b.add(@product3)
25     b.add(@product1)
26 
27     assert_equal 2, b.individual_items.size
28   end
29 
30 end
31 

As I’ve done here, it’s pretty common to name your test after the function you’re testing, so test_individual_items tests that the individual items function is “working”.

But what does “working” mean?

The second test clears that confusion up. By adding the word “should” into the name of the test case, we’re forcing ourselves to think about what we actually want the function to do before coding it.

The second test also has a desirable side effect. By thinking about what the function should do and by writing that down with the word should it highlights that our original function, individual_items, is badly named, and a better name would be distinct_items.

When

It’s likely you’re not going to only want to test the individual_items function when there are items in the basket. We could also want to test a total function that returns how much everything in the basket is going to cost me.

 1 
 2 class BasketTest < Test::Unit::TestCase
 3 
 4   def setup
 5     @product1 = Product.new(:name => 'Cheese', :price => 1.99)
 6     @product2 = Product.new(:name => 'Crisps', :price => 0.49)
 7     @product3 = Product.new(:name => 'Soap', , :price => 1.20)
 8   end
 9 
10   def test_should_only_return_distinct_products_that_have_been_added
11     b = Basket.new
12     b.add(@product1)
13     b.add(@product3)
14     b.add(@product1)
15 
16     assert_equal 2, b.individual_items.size
17   end
18 
19   def test_should_give_running_total_of_all_items_that_have_been_added_to_the_basket
20     b = Basket.new
21     b.add(@product1)
22     b.add(@product3)
23     b.add(@product1)
24 
25     assert_equal 3.19, b.total
26   end
27 
28 end
29 

These test names are getting too long and there’s some pretty obvious duplication going on. Here comes “When” to help out.

 1 
 2 class WhenItemsHaveBeenAddedToTheBasketTest < Test::Unit::TestCase
 3 
 4   def setup
 5     @product1 = Product.new(:name => 'Cheese', :price => 1.99)
 6     @product2 = Product.new(:name => 'Crisps', :price => 0.49)
 7     @product3 = Product.new(:name => 'Soap', , :price => 1.20)
 8 
 9     @b = Basket.new
10     @b.add(@product1)
11     @b.add(@product3)
12     @b.add(@product1)
13   end
14 
15   def test_should_only_return_distinct_products
16     assert_equal 2, @b.individual_items.size
17   end
18 
19   def test_should_give_a_running_total
20     assert_equal 3.19, @b.total
21   end
22 
23 end
24 

So, using the words When and Should can help your tests and implementation become more readable and more maintainable.

A great way of getting started with this kind of testing is by using shoulda thoughtbots excellent extension to TestUnit.

16 November 2009

Better testing, part 1 – Why we test

I’ve been testing web applications for a long time now and over the years I’ve been fortunate enough to work with some experienced, opinionated and above all excellent developers. Each of these developers has shaped and changed the way that I look at programming but the one thing that has developed and changed the most is my understanding of testing.
With that in mind I’ve decided to write a series of post describing what I’ve learnt.

Before I get into testing techniques it’s important to understand why testing makes your life and your customers lives better. If you don’t understand the reasons for testing it’s going to be unlikely that you’ll understand or appreciate the reasons for good testing and the techniques to achieve it.

What’s in it for me?

code CONFIDENCE

Imagine that you could run a program that tells you that your application is working as you originally intended. That’s what testing gives you.

Stop those pesky bugs coming back

If you’re not testing this has happened to you:
Boss : “We got a bug, will you have a look at it.”
Dev: “No probs boss”
3 minutes later …
Dev: “Boss, it’s sorted, let’s get it deployed.”
Boss: “Great work.”

3 months later …
Boss : “We’ve got a bug, I thought you said it was fixed?”
Dev : “Soz Boss, I’ll get it fixed.”
4 minutes later …
Dev: “Boss, it’s sorted, let’s get it deployed.”
Boss: “Good”

1 months later …
Boss : “That f*cking bug is back. Get it fixed!”
Dev : “Eeek, ok”
2 minutes later …
Dev: “Boss, it’s sorted, let’s get it deployed.”
Boss: “It’d better be”

repeat until fired …

better code

When testing, particularly with Test Driven Development, you’re forced to stop and think about the problem before you jump in and start hacking. This means that when you do start coding, you understand the problem, you only write the code you need and that code is clean and of a much higher quality for it.

living documentation

Imagine, a world where your documentation changes with you code. Stop dreaming, start testing.

it’s actually pretty fun

because of all of the above (and some games you can play like ping pong)

01 July 2009

Vigenere cypher in ruby

Some time ago I implemented the Vigenere as a first look at Python. For some time I’ve wanted to do the same thing in Ruby and I finally found time.

The tests:

 1 require 'test/unit'
 2 require 'vigenere_cipher'
 3 
 4 class VigenereCipherTest < Test::Unit::TestCase
 5 
 6   def test_should_encrypt_a_string
 7     plain_text = 'ATTACKATDAWN';
 8     expected_result = 'LXFOPVEFRNHR';
 9 
10     machine = VigenereCipher.new;
11     encrypted_string = machine.encrypt('LEMONLEMONLE',plain_text);
12 
13     assert_equal expected_result, encrypted_string
14   end
15 
16   def test_should_decrypt_a_string
17     expected_result = 'ATTACKATDAWN';
18     encrypted_message = 'LXFOPVEFRNHR';
19 
20     machine = VigenereCipher.new;
21     encrypted_message = machine.decrypt('LEMONLEMONLE',encrypted_message);
22 
23     assert_equal expected_result, encrypted_message
24   end
25 
26   def test_should_loop_around_the_key_when_it_is_short_than_the_text
27     plain_text = 'ATTACKATDAWN';
28     expected_result = 'JXLSLOSLMEOF';
29 
30     machine = VigenereCipher.new;
31     encrypted_string = machine.encrypt('JESS',plain_text);
32 
33     assert_equal expected_result, encrypted_string
34   end
35 
36 end

And the implementation:

 1 class VigenereCipher
 2 
 3   def encrypt(key, plain_text)
 4     transform(key, plain_text, 'encrypt')
 5   end
 6 
 7   def decrypt(key, encrypted_message)
 8     transform(key, encrypted_message, 'decrypt')
 9   end
10 
11 private
12   def transform(key, text, method)
13     n = -1
14     text.split(//).map{|letter| transform_letter(letter, calc_key_letter(key, n+=1), method=='encrypt' ? :+ : :- )}.join
15   end
16 
17   def transform_letter(letter, key_letter, plus_or_minus)
18     charset_offset = "A"[0]
19     letter_position = letter[0] - charset_offset
20     key_letter_position = key_letter[0]-charset_offset
21 
22     letter_shifts_by = letter_position.send(plus_or_minus, key_letter_position)
23     (letter_shifts_by.modulo(26)+charset_offset).chr
24   end
25 
26   def calc_key_letter(key, n)
27     n = n.modulo(key.length)
28     key.split(//)[n]
29   end
30 
31 end

If you’d like to download the code you can get it from my github account

23 June 2009

Converting an array of tuples to a hash

I was working with a class today that gave me an array of tuples:

1 person = [['name','craig'],['likes','climbing']]

I want to use this data to create an object so my code would be much prettier if I had a hash.

I thought converting this array of tuples to a hash would be messy but it’s not. You can create a hash from an array like so.

1 >> Hash['name','craig','likes','climbing']
2 => {"name"=>"craig", "likes"=>"climbing"}

Now that we know that, we can create a hash from an array of tuples.

1 >> tuples = [['name','craig'],['likes','climbing']]
2 => [["name", "craig"], ["likes", "climbing"]]
3 >> Hash[*tuples.flatten]
4 => {"name"=>"craig", "likes"=>"climbing"}
28 May 2009

Testing and generating HTML outside Rails views

At Reevoo we have cause to generate HTML snippets that are written to files rather than served up by a controller. It’s a pretty non-standard thing to do so I thought I’d share our methods (and if there’s a better way maybe someone will tell me).

First let’s look at the test:

(If you’re not familiar with Factory or should, take a look at Factory Girl and Shoulda)

 1 
 2 class WidgetHTMLGeneratorTest < ActiveSupport::TestCase
 3 
 4   include ActionController::Assertions::SelectorAssertions
 5 
 6   should "include the product name" do
 7     product = Factory(:product)
 8     html = WidgetHTMLGenerator.generate(product)
 9     assert_select HTML::Document.new(html).root, "div#product_name", product.name
10   end
11 
12 end
13 

Because we’re passing the HTML snippet in to assert_select we can assert our HTML markup in the same way we would in a controller or integration test, meaning we can test the markup that’s really important to us.

Now the implementation:

 1 
 2 class WidgetHTMLGenerator
 3 
 4   def self.generate(product)
 5     @product = product
 6     file_contents = File.read(File.join(Rails.root,'app','views','widget_html_generator','test.html.erb'))
 7     erb = ERB.new(file_contents)
 8     erb.result(binding)
 9   end
10 
11 end
12 

and the erb file:

1 
2 <div id='problem_name'><%= @product.name %></div>
3 
26 May 2009

The problem with TDD

Sometimes it’s hard to write tests before code. It’s easy when you have:

  • a clear understanding of the domain
  • an understand what the client wants to achieve
  • an understanding the API’s you’ll use to do the job

But it’s much harder to write good tests if you don’t.

One possible solution is something I’ve started referring to as Chris Roos Test Driven Development.

Given a problem or feature you’re unfamiliar with, a great first step is to prototype the solution. Pick the primary success criteria and hack at the system until you have it doing what you think it should. Don’t consider any edge cases and don’t write any tests, just make it do the simplest, dirtiest thing possible. Once you have a clear understanding of the code and the problem, REVERT! This is really important. Don’t be tempted to retrofit tests on top of your hack, that’ll result in bad testing and messy code. Take what you’ve learnt and start a fresh. This time write tests and consider edge cases. You’ll work much more quickly with an understanding of the system and you’re code, tests and overall solution will reap the benefit.

While working with Chris at Reevoo he often used this method which always resulted in clear, concise code and tests, which is why I’ve attributed it to him.

07 May 2009

Factory Girl for the win

In my last post I talked about testing and in this post I’d like to continue that theme.

As a classicist I like to create actual objects when I test. I find it makes my tests easier to write, shorter and more readable, but creating valid objects can be a messy business.

 1 class ProductControllerTest < ActionController::TestCase
 2   def test_should_show_price
 3     product = Product.create!(
 4                   :name => 'Dragons',
 5                   :brand => '5/10',
 6                   :sku => 'ABC',
 7                   :ean => '510DRAG',
 8                   :price => '75.00')
 9     
10     get :show, :sku => 'ABC'
11     assert_select '.price', '12.50'
12   end
13 end

In the test above we only care about the price and the sku of the product, having all these other attributes is messy but a valid Product requires all of them. It is necessary to create a valid object but we don’t need to do it in this clunky, verbose way. Enter the Object Mother

Essentially the Object Mother is just a factory for creating test objects that allows use to concentrate on the attributes we care about in the test.

 1 class Mother
 2   def self.create_product(attributes = {})
 3     Product.create!({
 4       :name => 'Product',
 5       :brand => 'Brand Name',
 6       :sku => 'SKU',
 7       :ean => 'EAN',
 8       :price => 10.00}.merge(attributes))
 9   end
10 end
11   
12 class ProductControllerTest < ActionController::TestCase
13   def test_should_show_price
14     product = Mother.create_product({:price => 75.00, :sku => 'ABC'})
15     
16     get :show, :sku => 'ABC'
17     assert_select '.price', '75.00'
18   end
19 end

Mission accomplished, the test is much more succinct because the data we created in the test is relevant to that test. But that’s not the end of the story. The example above is very simple, what if in our test we wanted 2 or more products and a valid product has unique EANs and SKUs.

Option 1) Pass the unique parts into the Mother – but that’ll pollute the test with irrelevant data again.
Option 2) Modify the Mother to dynamically create values for all the unique attributes
Option 3) Use something that already does Option 2 and a whole load of other things

Enter Factory Girl

 1 #tests/factories.rb
 2 Factory.sequence :sku do |n|
 3   "SKU#{n}"
 4 end
 5 Factory.sequence :ean do |n|
 6   "EAN#{n}"
 7 end
 8 Factory.define :product do |p|
 9   p.name "Product"
10   p.brand "Brand"
11   p.price 12.50
12   p.sku{ Factory.next :sku } #dynamically set the sku
13   p.ean{ Factory.next :ean } #dynamically set the ean
14 end
15 
16 #controller test
17 class ProductControllerTest < ActionController::TestCase
18   def test_should_show_price
19     product = Factory(:product, :price => 75.00, :sku => 'ABC')
20     
21     get :show, :sku => 'ABC'
22     assert_select '.price', '75.00'
23   end
24 end

Not only does Factory Girl do the job of make the test readable and relevant, it also handles sequences (like the ean and sku values), associates and more.

05 May 2009

The dangers of over mocking

Classicist vs Mockist approach to TDD is a classic and ongoing debate in the software community.

I’ve long been a classicist but I started out my career as a mockist.

Recently I came up against a particularly poignant example of the drawbacks of heavy mocking and wanted to share the experience.

The Mockists solution

1 class ProductControllerTest
2   def test_should_show_price
3     Product.stubs(:find_by_product_code).returns(stub(:price => 12.50))
4     
5     get :show, :product_code => 'IPOD'
6     assert_select '.price', '12.50'
7   end
8 end

In the test above we want to make sure that the controller shows the price on the product page. We don’t want to test ActiveRecord functionality so we stub out find_by_product_code. We implement the controller to use find by product code and our test passes. Great! Well not really.

Six month later another developer is refactoring. Everyone in the whole business refers to product_code as SKU, and all the developers keep getting confused so a rename is in order. One quick migration later, the rename is done and the test suit is running. Sadly our test above won’t fail, even though the column is gone leaving us with a meaningless test and broken code :(

The Classicists solution

1 class ProductControllerTest
2   def test_should_show_price
3     product = Product.create!(:price => 12.50, :product_code => 'IPOD')
4     
5     get :show, :product_code => 'IPOD'
6     assert_select '.price', '12.50'
7   end
8 end

Actually creating the object instead of mocks prevents your test being tied to your implementation and in the mockist case above, hiding potential errors.

30 April 2009

Interactive Rake

I often find myself using rake -T. I always have a vague idea of the name of the Rake task I’d like to run but often tasks with long names slip my mind. I’m also incredibly lazy and don’t want to type the entire name of the task if I don’t have to.
That’s why I decided I needed Interactive Rake. The ability to search though my tasks and then choose the one I’d like to run from a list.

For example, to search your tasks for the name “create”, then run rake tmp:create

1 craig:themoves.co.uk craig$ rake -i create
2 (in /Users/craig/rails_sites/themoves.co.uk)
3 0) rake db:create           # Create the database defined in config/database.yml for the current RAILS_ENV
4 1) rake db:create:all       # Create all the local databases defined in config/database.yml
5 2) rake db:sessions:create  # Creates a sessions migration for use with ActiveRecord::SessionStore
6 3) rake tmp:create          # Creates tmp directories for sessions, cache, sockets, and pids
7 Choose a task: 3

Sadly Jim Weirich is being elusive so I’m having trouble getting my fork merged back in to the trunk. If you’d like to use Interactive Rake it’s hosted at github.com/craigmarksmith/rake

03 July 2008

Agile Icecream

icecream

A new restaurant has recently opened up close to Ominors office. That’s nothing new you might say, since the office is on Chiswick High Road, but this restaurant is a little different.

Originally the premises had been a knickknacks shop selling season bits and pieces, seasonal tat, some might call it. As soon as Christmas had ended their fate was inevitable and had closed by the end of February. Our intrepid restaurateurs started to convert the old shop some time in June and to my amazement opened about a week and a half later. Amazing I thought, how could they have possible have completely overhauled a shop, installed a kitchen and employed a chef in such a small amount of time?

The answer was simple, they hadn’t!

On my first visit, they simply had a small ice cream booth at the front of the shop, which was generating a fair amount of attention from some local kids, and a sign saying “Coming Soon” in what would be the dinning area.

To me this is the perfect example of Agile in action. BLAH have delivered business value by doing the simplest thing that works and are, most importantly, making money.

13 October 2007

Clarity

I love that feeling, the one where you’ve done something for years, known it was the right thing to do but never been able to prove it, until that moment. You’ve just taken the word of others and trusted their experience and then, suddenly, it all makes sense and you know you where right to follow your instincts and place your trust in that person.

That ‘clarity’ has happened to me many times during my professional career but a fairly important one happened just a few weeks ago.

I’ve been rewriting my main website (themoves) on and off for around 4 years now. As soon as I finish a version I almost immediately start the next. The functionality over the years hasn’t changed but under the hood, the code is getting smarter, cleaner, faster and maybe one of these days I might even be confident enough to show it to someone.
It’s during this fourth rewrite that I had my most recent ‘attack’ of ‘clarity’. The difference with this version is that it’s test driven (TDD).

I’ve always understood and trusted the reasons for automated testing and TDD:

  • Code confidence
  • Good test == good code
  • Tests == documentation
  • You only write what you need
  • Helps break your code into smaller deliverables

Up until now (well, a fair while ago but now being the moment of ‘clarity’), reason 4 was lost on me. Surely I only write the code that I need. I’m not the sort of guy who over engines, I’m way too lazy for that. I write the bare minimum so my app does what I need then forget it. I’ve got way too much climbing to do to waste my time doing anything I don’t need to. This rule doesn’t apply to me!!!

WRONG!

Themoves3, the current live version of the site was, in my eyes, a disaster. It look ages to write and didn’t do anything that themoves2 didn’t. It’s almost exactly the same except some variables have been moved around and some methods have been moved into their own objects. Most professionals call this a Refactor but I had to rewrite because I had no code confidence. It was a total disaster because themoves3 also didn’t have any test, hens, themoves4 was born.

The clarity came when I was writing the Configuration class, a simple object that allows me to access configuration options such as DB user name, passwords etc. I found that, when I was reimplementing this class, the code I was writing was cleaner and I was writing less of it. In fact, the new class was 25% shorter. The reason was simple. By writing tests I’d been forced to think about exactly what I wanted before starting to code. I wasn’t coding and thinking and inventing all at the same time, so by breaking up the requirements into test I got exactly what I wanted, not what I thought I wanted.

So, if you’re reading this and not writing test for your current app then STOP and start writing some. If you don’t see why at the moment please, TRUST me, you’ll be glad you did.

20 September 2007

A first look at Python

Around a year ago I read the O’Reilly ‘Learning Python’ book and since then I’ve been looking for a quick, interesting and easy challenge to put it to use.

Around two years ago a friend bought me a copy of “The Code Book – the secret history of codes and code-breaking” by Simon Singh. At the time I thought “cheers, that looks dull”, but as usual I was completely wrong. It’s probably one of the most interesting books I’ve ever read. Even better than Alex James autobiography and everyone knows I love that since for about 3 months all I talked about was carrots and 120bpm.

Anyway, The Code Book introduced me to the Vigenere Cipher, a method that uses a key phrase to encrypt any plain text. This encryption method seemed like a great opportunity to put together a little code that takes a key phrase and some plain text and encrypts one with the other.

Heres my attempt.

The unit test:

 1 import unittest;
 2 from CypherMachine import *;
 3 
 4 class CypherMachineTest(unittest.TestCase):
 5 
 6   def test_encrypt(self):
 7     test_string     = 'thisisateststring';
 8     expected_result = 'clabmkjxwbxkcvawk';
 9 
10     machine = CypherMachine();
11     encrypted_string = machine.encrypt('jes',test_string);
12 
13     assert encrypted_string == expected_result
14 
15 
16 if __name__ == "__main__":
17   unittest.main();

The implementation:

 1 class CypherMachine:
 2   def encrypt(self,key,plain_text):
 3     encrypted_text = ''
 4 
 5     position = 0
 6     while position < len(plain_text):
 7       for key_letter in key:
 8         if position == len(plain_text):
 9           break
10         encrypted_text = encrypted_text + self.encryptLetter(key_letter,plain_text[position])
11         position = position + 1
12 
13     return encrypted_text
14 
15   def encryptLetter(self,key_letter,plain_letter):
16 
17     key_position = ord(key_letter)
18     plain_letter_position = ord(plain_letter)
19 
20     #96 being the number to bring lower case letters to there position in the alphabet
21     #-1 since the cyper square starts with b
22     key_alphabet_position = ord(key_letter) - 96 - 1
23 
24     encrypted_position = plain_letter_position + key_alphabet_position
25 
26     if encrypted_position > ord('z'):
27       encrypted_position = encrypted_position - 26
28 
29     encrypted_letter = chr(encrypted_position)
30     return encrypted_letter

I know it’s not as neat or as simple as it should be but for an hours work I’m pretty happy with it. I love that fact that in Python you don’t waste time typing inconsequential characters like ‘{’ and ‘;’. I also like the fact that the parser makes you indent your code properly. But the best thing about Python is how easy it was to test. If I’d written this class in PHP I would have had to downloaded Simpletest or PHPUnit, read a little about how they work (to be fair, they’re both easy to use), find and included the files I wanted, then get on with the job of coding. With Python it’s just so easy. Import the unittest modules and get on with it. Perfect!

Maybe if testing in PHP was this easy I’d get fewer dirty looks when I tell people I’m a PHP developer.