Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Tree: a83b7afcb0
Fetching contributors…
Cannot retrieve contributors at this time
300 lines (192 sloc) 11 KB
<meta charset="utf-8">
<title>How I test part II - testing models - Entreprevelopment adventures</title>
<meta name="author" content="Luisa Lima">
<meta name="description" content="Testing models From rails guides: &#8220;Ideally, you would like to include a test for everything which could possibly break. It’s a good practice to &hellip;">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="/atom.xml" rel="alternate" title="Entreprevelopment adventures" type="application/atom+xml">
<link rel="canonical" href="">
<link href="/favicon.png" rel="shortcut icon">
<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//"></script><![endif]-->
<script src="//"></script>
<header id="header" class="inner"><h1><a href="/">Entreprevelopment adventures</a></h1>
<nav id="main-nav"><ul class="main">
<li><a href="/">Blog</a></li>
<li><a href="/blog/archives">Archives</a></li>
<nav id="mobile-nav">
<div class="alignleft menu">
<a class="button">Menu</a>
<div class="container"><ul class="main">
<li><a href="/">Blog</a></li>
<li><a href="/blog/archives">Archives</a></li>
<div class="alignright search">
<a class="button"></a>
<div class="container">
<form action="" method="get">
<input type="text" name="q" results="0">
<input type="hidden" name="q" value="">
<nav id="sub-nav" class="alignright">
<div class="social">
<a class="twitter" href="" title="Twitter">Twitter</a>
<a class="github" href="" title="GitHub">GitHub</a>
<a class="rss" href="/atom.xml" title="RSS">RSS</a>
<form class="search" action="" method="get">
<input class="alignright" type="text" name="q" results="0">
<input type="hidden" name="q" value="">
<div id="banner" class="inner">
<div class="container">
<ul class="feed"></ul>
<small><a href="">luisamoyalima</a> @ <a href="">Twitter</a></small>
<div class="loading">Loading...</div>
<script src="/javascripts/twitter.js"></script>
<script type="text/javascript">
$('#banner').getTwitterFeed('luisamoyalima', 4, false);
<div id="content" class="inner"><article class="post">
<h2 class="title">How I Test Part II - Testing Models</h2>
<div class="entry-content"><h2>Testing models</h2>
<p>From <a href="">rails guides</a>:</p>
<p>&#8220;Ideally, you would like to include a test for everything which could possibly break. It’s a good practice to have at least one test for each of your validations and at least one test for every method in your model.&#8221;</p>
<p>Which leads me to&#8230;</p>
<h2>Why I use shoulda</h2>
<p>I think that the best thing is just to take a peek at <a href="">The shoulda cheat sheets</a>.</p>
<p>You actually get a guide of what to test by looking at the cheat sheet! It&#8217;s too bad that it&#8217;s not up to date (actually I think that the whole site is not up to date &#8211; even the gem doesn&#8217;t work anymore, which I think is too bad :-( )</p>
<p>Furthermore, it&#8217;s great for lazy people and it&#8217;s definitely easier on the eyes. Just check the following example:</p>
<script src="">
<div><script src=''></script>
<noscript><pre><code># without shoulda... tons of code :-)
it &quot;should belong to person&quot; do
Model.reflect_on_association(:person).macro.should == :belongs_to
# with shoulda... one-liner!
it{should belong_to(:person)}
<p>Convinced? ;-)</p>
<h2>What I test exactly with shoulda</h2>
<p>I go through the whole list of shoulda macros for models, and I just use and abuse them. Since the cheat sheet is not up to date, I created a new one (just for models for now) at:</p>
<div><script src=''></script>
<noscript><pre><code># updated from the original @
# just a subset -- models -- is included here. I'll update this, and create cheat sheets for others, as I go along.
# I marked the ones I added with NEW and also added the links to the corresponding code, as I think it's useful.
# Any comments/corrections are welcome!
# ================= Data and Associations =======================
it { should_not have_db_column(:admin).of_type(:boolean) }
it { should have_db_column(:salary).
with_options(:precision =&gt; 10, :scale =&gt; 2) }
it { should have_readonly_attributes(:password) }
it { should belong_to(:parent) }
it { should have_db_index(:id) } # NEW
it { should have_many(:friends) }
it { should have_many(:enemies).through(:friends) }
it { should have_many(:enemies).dependent(:destroy) }
it { should have_one(:god) }
it { should have_and_belong_to_many(:posts) }
it {should accept_nested_attributes_for(:user)} # NEW
# ================== Validation Matchers ============================
it { should validate_uniqueness_of(:keyword) }
it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
it { should validate_uniqueness_of(:email).scoped_to(:name) }
it { should validate_uniqueness_of(:email).
scoped_to(:first_name, :last_name) }
it { should validate_uniqueness_of(:keyword).case_insensitive }
it { should validate_presence_of(:name) }
it { should validate_presence_of(:name).
with_message(/is not optional/) }
it { should validate_numericality_of(:age) }
it { should validate_format_of(:name).
with_message(/is not optional/) }
it { should validate_format_of(:name).
with_message(/is not optional/) }
it { should validate_acceptance_of(:eula) }
it { should ensure_length_of(:password).
is_at_most(20) }
it { should ensure_length_of(:name).
with_short_message(/not long enough/) }
it { should ensure_length_of(:ssn).
with_message(/is invalid/) }
it { should ensure_inclusion_of(:age).in_range(0..100) }
it { should_not allow_mass_assignment_of(:password) }
it { should allow_mass_assignment_of(:first_name) }
it { should validate_format_of(:first_name).with(&quot;Carl&quot;) }
it { should validate_confirmation_of(:password) } # NEW</code></pre></noscript></div>
<p>Yes, it&#8217;s a bit tedious. But (1) you make sure that you are actually testing all these details, which is extremely useful when you are constantly refactoring your code, and (2) it&#8217;s not that slow with the multiple cursors of Sublime Text 2. You just need to have a scaffold.</p>
<h2>What I test without shoulda</h2>
<p>Apart from model methods, is there that much to test without shoulda? I test:</p>
<li>Any model methods, extensively</li>
<li>Callbacks, extremely extensively</li>
<li>Some validations - but just to make sure I coded them right. See more of this perspective in <a href="">Testing model validations in rspec the short and sweet way</a></li>
<p>&#8230; and for now, that&#8217;s about it.</p>
<h2>Regarding generating fake data</h2>
<p>Like I mentioned before, I do use FactoryGirl extensively. Maybe that means that <a href="">my models are complicated</a>? I don&#8217;t know, but for now, I am sort of using good sense and stuff. Let&#8217;s see what happens. I do use <a href="">Faker</a> as well. Come to think about it, will do a post on that eventually.</p>
<h2>Random issues in testing models</h2>
<p>When everything seems to be absolutely correct in the models and in the tests and you are still getting unexplainable errors, do restart guard. I already spent several hours messing around with the tests because guard didn&#8217;t refresh the models. <a href="">There are automatic solutions</a>, but I didn&#8217;t feel like hacking away the spork/guard configurations again&#8230; yet.</p>
<h2>Random resources</h2>
<li><p><a href="">Everyday Rails: How I learned to test my Rails applications, Part 3: Model specs</a> - this has a very nice overview of the actual steps required to test models. Now I just cheat using shoulda, but it&#8217;s very nice and useful to get a</p></li>
<li><p><a href="">Testing model validations in rspec the short and sweet way</a> - it&#8217;s a bit outdated, but describes how to test validations in a short way.</p></li>
<hr />
<p>Again, as I already mentioned, I am a beginner to rails and, consequently, in testing rails, so I might be doing/saying terribly wrong things. Any input is very much appreciated :-)</p>
<div class="meta">
<div class="date">
<time datetime="2012-12-19T10:17:00+00:00" pubdate data-updated="true">Dec 19<span>th</span>, 2012</time></div>
<div class="tags">
<a class='category' href='/blog/categories/tdd/'>TDD</a>, <a class='category' href='/blog/categories/rails/'>rails</a>, <a class='category' href='/blog/categories/rails-tips/'>rails_tips</a>, <a class='category' href='/blog/categories/rspec/'>rspec</a>, <a class='category' href='/blog/categories/testing/'>testing</a>
<div class="share">
<div class="addthis_toolbox addthis_default_style ">
<a class="addthis_button_tweet"></a>
<a class="addthis_counter addthis_pill_style"></a>
<script type="text/javascript" src=""></script>
<footer id="footer" class="inner">Copyright &copy; 2012
Luisa Lima
<script src="/javascripts/slash.js"></script>
<script src="/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
</script> <!-- Delete or comment this line to disable Fancybox -->
Jump to Line
Something went wrong with that request. Please try again.