At the Forge - RSpec
Let's create a slightly more sophisticated version of the person model:
./script/generate rspec_model person first_name:text \
last_name:text email_address:text phone_number:text \
sex:text
This creates a migration, which you can use to create the first version of your person model:
rake db:migrate
Now, it's true that you should go into the migration file and modify things, such that (for example) the person's name, e-mail address and sex are all mandatory. However, let's ignore that step for now and assume that you want all of your validation logic to be at the application layer. In such a case, you would want to put some validations in the model file.
Well, you could do that, but that wouldn't be very BDD of you, would it? Rather, you should imagine the specification that a consumer, or the manager, might want from a “person” object, and then build the object up to adhere to those standards.
For example, you might want to ensure the presence of the first and last names. So, the first file to modify is spec/models/person_spec.rb, rather than app/models/person.rb. (For reasons I don't quite understand, Test::Unit calls model tests unit tests, and RSpec calls them model tests, and the controller tests are called functional tests.) If you open that file, you'll see a new, bare-bones specification:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Person do
before(:each) do
@valid_attributes = {
:first_name => "value for first_name",
:last_name => "value for last_name",
:email_address => "value for email_address",
:phone_number => "value for phone_number",
:sex => "value for sex"
}
end
it "should create a new instance given valid attributes" do
Person.create!(@valid_attributes)
end
end
You can run your full suite of specs at any time, by typing:
rake spec
The first line imports anything defined in spec_helper, which I mentioned earlier. Next comes a describe line; this will be familiar to those of you who have looked at Shoulda. The basic idea is that someone reading the specification reads the argument to “describe” and then reads each of the individual specifications that start with “it”. In other words, this spec file tries to say “Person should create a new instance given valid attributes.” And, sure enough, it does.
The before(:each) block tells RSpec what it should invoke before each “it” block. This ensures that the @valid_attributes instance variable will be set to a predictable value before running each spec. You then can modify @valid_attributes as necessary within each spec, as you will soon see.
The thing is, you're checking the validity of your specification by creating a new instance of Person. You can do that, but if the spec fails, you will end up with a code backtrace mixed in with your report. For this reason, I'm going to change the existing spec definition to look like this:
it "should create a new instance given valid attributes" do p = Person.new(@valid_attributes) p.should be_valid p.save.should_not == false end
Instead of Person.create, you now are invoking Person.new, assigning it to the variable p. Let's check p in two different ways, once using should and the other using should_not. These methods are mixed in by RSpec to the Object class and contain a great deal of behind-the-scenes magic to make specifications readable, almost as if they were in plain English. For example, when you say:
p.should be_valid
RSpec's should method looks for a method named valid? for that object and checks that the invocation of this method returns true. This works for any predicate (that is, method that returns true or false). If should or should_not is followed by be_XXX, RSpec turns that into a method call of XXX? on the object instance.
So, you can understand what it means to say:
p.save.should_not == false
which you equivalently could write in a more positive, optimistic way:
p.save.should == true
In both cases, you invoke the save method on the object and check that its returned value is true. You might argue that you don't need to invoke both new and save on your object, but I like to make sure the object is valid in both Ruby and the database. After all, it could be that you told the database to reject null values, but that you allowed it using validations in your ActiveRecord definition.
Now let's move a bit beyond the defaults to set some limits on attributes. Presumably, you want people in your database to have all of these fields (first name, last name, e-mail address, phone number and sex) defined. If you were developing in a non-TDD/BDD way, you first would set up validations for all of those and then add some tests. But, here you're trying to write tests first, thinking from the “outside” how your object might behave. And indeed, each person should have a first name, a last name, an e-mail address and a telephone number. (Strange as it might seem now, there was once a time when having an e-mail address was not expected.)
So you could, for example, include the following:
it "should not be valid without a first name" do @valid_attributes.delete[:first_name] p = Person.new(@valid_attributes) p.should_not be_valid p.save.should == false end
In other words, you take @valid_attributes, remove the :first_name key from it and then create a new person with the rest of the name-value pairs from @valid_attributes. This should not work, because everyone needs a first name. But when I run the specs, I get:
1) 'Person should not be valid without a first name' FAILED expected valid? to return false, got true ./spec/models/person_spec.rb:23: Finished in 0.038731 seconds 2 examples, 1 failure
In other words, the specification failed. But that's okay—that's precisely what you want when you're working in BDD fashion. You wrote a test, it failed, and now you can go into the code and modify it, so as to ensure that the test passes. Ensuring that this current test passes is a simple matter of adding a validation to your ActiveRecord model. Instead of being the empty default:
class Person < ActiveRecord::Base end
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
- RSS Feeds
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Download the Free Red Hat White Paper "Using an Open Source Framework to Catch the Bad Guy"
- Home, My Backup Data Center
- Tech Tip: Really Simple HTTP Server with Python
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




1 hour 44 min ago
3 hours 59 min ago
4 hours 27 min ago
5 hours 26 min ago
6 hours 54 min ago
8 hours 3 min ago
8 hours 49 min ago
15 hours 25 min ago
21 hours 4 min ago
1 day 3 hours ago