You’ve probably heard of the idea of a “code smell” – a hint that something in the code is not quite right and ought to be changed.

Just as there are code smells, there are “test smells”. The book xUnit Test Patterns describes a number of them.

One of the smells described in the book is Obscure Test. An Obscure Test is a test that has a lot of noise in it, noise that’s making it hard to discern what the test is actually doing.

Here’s an example of an Obscure Test I wrote myself:

context 'the element does not exist' do before do contents = %( <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"> <channel> <item></item> </channel> </rss> ) xml_doc = Nokogiri::XML(contents) episode_element = xml_doc.xpath('//item').first @rss_feed_episode = RSSFeedEpisode.new(episode_element) end it 'returns an empty string' do expect(@rss_feed_episode.content('title')).to eq('') end end

There’s a lot of noise in the contents variable (e.g. <?xml version="1.0" encoding="UTF-8"?> ). All that stuff is irrelevant to what the test is actually supposed to be testing. All this test should really care about is that we have an empty set of tags.

Here’s a refactored version of the same test:

context 'the element does not exist' do let(:rss_feed_episode) do RSSFeedEpisodeTestFactory.create("<item></item>") end it 'returns an empty string' do expect(rss_feed_episode.content('title')).to eq('') end end

Hopefully this is much more clear. The gory details of how to bring an RSS feed episode into existence are abstracted away into RSSFeedEpisodeTestFactory, a new class I created. Here’s what that class looks like:

class RSSFeedEpisodeTestFactory def self.create(inner_contents) @inner_contents = inner_contents rss_feed_episode end def self.rss_feed_episode RSSFeedEpisode.new(xml_doc.xpath('//item').first) end def self.xml_doc Nokogiri::XML(contents) end def self.contents %( <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"> <channel>#{@inner_contents}</channel> </rss> ) end end

Now I can use this factory class wherever I like. It not only helps me keep my tests more understandable but also helps cut down on duplication.

In the video below you can watch me refactor the “obscure” version into the more readable version as part of one of my free live Rails testing workshops.



​