Test fixtures and behavioral testing
Yesterday, I was coding a new set of tests for a Picture class. I wanted to introduce an on-disk cache, when the picture is public.
I already had an existing test/unit/picture_test.rb, which I extended.
The tests looked like this:
test/unit/picture_test.rb
1 class PictureTest < Test::Unit::TestCase 2 def test_picture_exists_on_disk 3 pict = uploaded_file('large.jpg', 'image/jpeg', 'somepicture.jpg') 4 @picture = Picture.build(pict) 5 @picture.public = true 6 assert_model_saved @picture 7 8 assert File.exist?(@picture.cache_filename), 'file copied to disk' 9 end 10 11 def test_thumbnail_exists_on_disk 12 pict = uploaded_file('large.jpg', 'image/jpeg', 'somepicture.jpg') 13 @picture = Picture.build(pict) 14 @picture.public = true 15 assert_model_saved @picture 16 17 assert File.exist?(@picture.cache_thumbnail), 'file copied to disk' 18 end 19 end
I knew this was the wrong way to go – the fixture was repeated more than once. Then, I realized that what I wanted was a new TestCase. I had already reached for my mouse to hit New File when I had a flash: what prevents me from simply adding a new class to picture_test.rb ?
test/unit/picture_test.rb
1 class PictureTest < Test::Unit::TestCase 2 def test_read_from_stringio 3 ... 4 end 5 end 6 7 class PublicPictureTest < Test::Unit::TestCase 8 def setup 9 pict = uploaded_file('large.jpg', 'image/jpeg', 'somepicture.jpg') 10 @picture = Picture.build(pict) 11 @picture.public = true 12 assert_model_saved @picture 13 end 14 15 def test_picture_exists_on_disk 16 assert File.exist?(@picture.cache_filename), 'file copied to disk' 17 end 18 19 def test_thumbnail_exists_on_disk 20 assert File.exist?(@picture.cache_thumbnail), 'thumbnail copied to disk' 21 end 22 end 23 24 class PrivatePictureTest < Test::Unit::TestCase 25 include PicturePathHelper 26 27 def setup 28 pict = uploaded_file('large.jpg', 'image/jpeg', 'somepicture.jpg') 29 @picture = Picture.build(pict) 30 @picture.public = false 31 assert_model_saved @picture 32 end 33 34 def test_picture_not_copied_to_disk_when_private 35 assert !File.exist?(@picture.cache_filename), 36 'image should not be on disk when picture is private' 37 end 38 39 def test_thumbnail_not_copied_to_disk_when_private 40 assert !File.exist?(@picture.cache_thumbnail), 41 'thumbnail should not be on disk when picture is private' 42 end 43 end
I also had another flash: is TestCase the right name ? Shouldn’t it be called TestFixture instead ? Because that is what instances of this class represent – a test fixture.
This is very much akin to Spec::Context, from RSpec.
And you see the tests ? They all respect the one assertion per test. I was quite happy with the results.
Now, I need to refactor those other instances in my test suite…