# Rails Partial Tests

**URL:** <https://www.ruby-forum.com/t/rails-partial-tests/150181>\
**Category:** Rails\
**Created:** [October 5, 2008, 1:33pm UTC](https://www.ruby-forum.com/t/rails-partial-tests/150181 "2008-10-05T13:33:46Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [October 5, 2008, 1:33pm UTC](https://www.ruby-forum.com/t/rails-partial-tests/150181/1 "2008-10-05T13:33:46Z")

</div>

[A preview of my next blog entry]

Testing Rails Partials

```
One important metric, under Test Driven Development, is the distance
between a test case and its target code. Test cases use assertions 

```

to  
observe events inside programs. If a test case requires more than a  
few  
hops to reach its target event, the intermediate methods can add  
noise  
to the test’s signal.

```
Some architectures make decoupling test cases very hard. This post
develops a fix for an icky Rails problem - testing one small partial
.rhtml file embedded in a huge web page.

```

Rails View Testing

```
Rails projects can test web pages by rendering them to HTML, then
diverting them into test cases. Rails functional tests can get
controller actions, then parse web pages, returned in 

```

@response.body,  
to match important details.

```
(If your web pages are pure XHTML [a very good idea], you can test 

```

them  
with assert\_xpath. If they are not, call assert\_tidy before  
assert\_xpath.)

```
Anything your production code pushes into a web page, with <%= %> 

```

eRB  
tags, a test should pull out, using assert\_match, assert\_xpath, or  
assert\_select.

```
However, such tests can be noisy. A test that detects an important
number, such as 42 in an input field, should not trip over any
irrelevant 42s, such as a nearby <img width='42'>. When tests run
closer to their tested code, their signal gets stronger.

Rails can generate HTML by pushing .rhtml files (or .html.erb files)
together with layout files and partial files. A partial is Rails's 

```

unit  
of HTML reuse. A Rails View can render a partial and insert it into  
its  
hosting HTML like this:  
\<%= render :partial =\> “photos/show” %\>

```
Test Driven Development works best when each test case targets one
aspect of a class's interface. So this post will demonstrate a 

```

simple  
and direct way to test a partial without testing the Views, layouts,  
and Controller actions surrounding it. On very complex projects,  
this  
technique keeps your partials decoupled.

```
This is the Photo Gallery project from [1]Ajax on Rails, by Scott
Raymond. I upgraded it to use Rails 2.1, yet these techniques all 

```

work  
freely with any Ruby on Rails version \>1.4. Then I added a simple  
test  
to its action that shows a gallery of thumbnails:

require File.dirname( **FILE** ) + ‘/…/test\_helper’  
require ‘albums\_controller’  
require ‘assert\_xpath’  
require ‘assert2’

class AlbumsController; def rescue\_action(e) raise e end; end

class AlbumsControllerTest \< ActionController::TestCase  
include AssertXPath  
fixtures :albums, :photos # add a couple real fixtures here first!

def test\_show  
album = albums(:first)  
get :show, :id =\> album.id

```
 assert_xpath :div, :photos, 'find <div id="photos">' do
   assert_xpath :'ul/li', album.photos.first.id,
                             'finds <ul><li id="999">' do
     assert{ assert_xpath(:a)[:onclick] =~ /Photo.show/ }
   end
 end

```

end

end

```
The line with get :show, :id => album.id simulates a user hitting 

```

the  
show action with the id of a photo album. The page comes back in the  
secret variable @response.body with the rendered HTML.

An XPath DSL

```
The first assert_xpath converts that HTML into an XML document. The
notation :div, :photos is one of assert_xpath's Domain Specific
Language shortcuts. It expands to the complete XPath '//div[ @id =
"photos" ]'. You could write all that too, if you wanted.

When assert_xpath's first argument is a 'string', it evaluates as 

```

raw  
XPath. When it’s a :symbol, assert\_xpath tacks a // on the beginning  
(or the equivalent), meaning “seek any such node at or below the  
current node”.

```
Both forms of assert_xpath return only one node - the first one
encountered.

The last argument to assert_xpath is a diagnostic string. When
assert_xpath fails, it prints out this string, decorated with the
current HTML context.

When you call assert_xpath with a block, it narrows that context to
that block. Any assert_xpath calls inside that block can only match
HTML elements inside that container.

If the line assert_xpath :'ul/li'... failed, it would spew out only 

```

the  
contents of

. This is very important in Web  
development, because a complete HTML page could be several screens  
long. Most of it would not relate to the tested feature.

```
In summary, that test case detects this HTML:

```

…

  

  
-   
…  
  

  

…

```
I replaced the elements it did not detect with ... ellipses. Further
assertions could easily pin down their contents, if they were
important.

```

Cut to the Chase

```
The code which generated that HTML looks like this:

```

\<%= render :partial =\> "photos/index" %\>

```
That looks mostly harmless, but imagine if all the other show.rhtml
business around it were heavy and expensive; fraught with 

```

side-effects.  
Imagine if we needed to add an important feature into that partial,  
requiring many test cases. Each test case would have to call extra  
code  
to support those side-effects. Expensive test setup is a design  
smell -  
it indicates code that’s too coupled. When tests run close to their  
target code, they help it decouple.

```
Here's how to test that partial directly:

```

class ApplicationController  
def \_renderizer; render params[:args]; end  
end

class ActionController::TestCase # or Test::Unit::TestCase, for Rails  
\<2.0  
def render(args); get :\_renderizer, :args =\> args; end  
end

```
...

```

def test\_photo\_index  
album = albums(:first)

```
 render :partial => 'photos/index',
         :locals => { :@album => album }

 assert_xpath :'ul/li', album.photos.first.id,
                           'finds <ul><li id="999">' do
   assert{ assert_xpath(:a)[:onclick] =~ /Photo.show/ }
 end

```

end

```
That wasn't too horrifying now was it?

In general, Rails's internal architecture can be labyrinthine. 

```

That’s  
the price of incredible flexibility. Writing your own copy of render  
is  
hard, because a test using ActionController::TestCase does not yet  
have  
an ActiveView context. The test method get must concoct one using  
the  
same procedures as a real web hit.

```
To bypass this problem, we first add a secret action to all 

```

controllers  
- \_renderizer. Because Ruby is extensible, the runtime application  
never sees this method. It only appears under test. We implement  
render  
by packing up its arguments, passing them thru get to \_renderizer,  
and  
letting it call render.

```
The benefit is our test case requires one less assertion. A more
complex application could have avoided much more cruft there. And if
our assert_xpath failed, now, its diagnostic would report only the
partial's own contents.

And the mock render can generate any other View-level thing, 

```

isolating  
it for test. For example, it could test that our application layout  
has  
a link called “Gallery”, like this:

def test\_layout  
render :layout =\> ‘application’, :nothing =\> true  
assert\_xpath :‘a[. = “Gallery”]’  
end

```
This lightweight solution to a tricky Rails problem illustrates how
Ruby applications in general, and Rails in particular, reward 

```

thinking  
outside the box.

References

```
1.

```

[http://examples.oreilly.com/9780596527440/Ajax\_on\_Rails\_Example\_Applications.zip](http://examples.oreilly.com/9780596527440/Ajax_on_Rails_Example_Applications.zip)

–  
Phlip

---

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [October 6, 2008, 1:12am UTC](https://www.ruby-forum.com/t/rails-partial-tests/150181/2 "2008-10-06T01:12:07Z")

</div>

Did you have a question? I might be mistaken… but I’m not sure the  
purpose of rails-talk is to submit your blog posts.

On Sun, Oct 5, 2008 at 4:32 AM, Phlip [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> irrelevant 42s, such as a nearby ![](). When tests run  
> and direct way to test a partial without testing the Views, layouts,  
> require ‘assert\_xpath’  
> get :show, :id =\> album.id
> 
> current HTML context.  
> In summary, that test case detects this HTML:  
> important.  
> requiring many test cases. Each test case would have to call extra code  
> class ActionController::TestCase # or Test::Unit::TestCase, for Rails \<2.0  
> assert\_xpath :‘ul/li’, album.photos.first.id,  
> an ActiveView context. The test method get must concoct one using the  
> our assert\_xpath failed, now, its diagnostic would report only the
> 
> Phlip
> 
> >

–  
Robby R.  
Chief Evangelist, Partner

PLANET ARGON, LLC  
design // development // hosting

> **[Planet Argon](https://www.planetargon.com/)**
>
> Planet Argon is a Ruby on Rails development agency specializing in maintenance and support for existing Rails apps. Based in Portland, OR, Planet Argon has been a member of the Rails community since 2004.

[http://www.robbyonrails.com/](http://www.robbyonrails.com/)  
aim: planetargon

+1 503 445 2457  
+1 877 55 ARGON [toll free]  
+1 815 642 4068 [fax]

---

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [October 9, 2008, 5:07pm UTC](https://www.ruby-forum.com/t/rails-partial-tests/150181/3 "2008-10-09T17:07:04Z")

</div>

> [A preview of my next blog entry]

Aaaaand - if I can trust the new blogging system there - my next blog  
entry is up:

> **[Radar - O’Reilly](https://www.oreilly.com/radar/)**
>
> Now, next, and beyond: Tracking need-to-know trends at the intersection of business and technology

–  
Phlip
