On Bloopist, my blogging platform, I use the Ruby Gem Impressionist to track how many views each post gets. I've been experimenting with adding tests to Bloopist's code base. I want to make it less likely that adding a feature will break the site.
One particular feature that broke was the Popular Posts box. The Popular Posts box is supposed to show a blog's posts that got the most views. This feature broke once when I refactored some code. I thought that was the perfect time to add another test to the Bloopist code base. I wrote a test to make sure that the posts in the popular posts box were in fact the posts with the most views. Obviously this test failed when I wrote it. Then I fixed the feature, and my test started passing. I pushed the updates to the site, and voila, the feature was working again.
Here's my setup for getting tests with Impressionist to work with RSpec. Please comment if you see any ways this can be improved.
(Note: I use the Faker gem to create random dummy data for my database objects during testing.)
# spec/models/blog_spec.rb
require 'spec_helper'
require 'rails_helper'
describe "Blog" do
# ...
context "with posts" do
before :each do
@user = FactoryGirl.create(:user_with_blog)
@blog = @user.blogs.first
@posts = 10.times.map{FactoryGirl.create(:post_with_impressions, author: @user, blog: @blog)}
end
it "returns popular posts" do
popular_posts = @blog.popular_posts
last_impression_count = popular_posts.first.impressions_count
popular_posts.each do |post|
expect(post.impressions_count).to be <= last_impression_count
last_impression_count = post.impressions_count
end
end
end
end
# spec/factories.rb
FactoryGirl.define do
factory :user do
email {Faker::Internet.email}
username {Faker::Internet.user_name}
password {Faker::Internet.password}
factory :user_with_blog do
after(:create) do |user|
blog = create(:blog)
create(:blog_permission, user: user, blog: blog)
end
end
end
factory :blog do
name {"#{Faker::Book.author}'s Blog"}
subdomain {Faker::Lorem.word}
end
# ...
factory :post do
title {Faker::Book.title}
body {Faker::Lorem.paragraphs.join("\n\n")}
association :author, :factory => :user
association :blog
published_at {Faker::Time.between(DateTime.now - 1, DateTime.now + 1)}
factory :post_with_impressions do
after(:create) do |post|
rand(10).times do
create(:impression, impressionable: post)
end
end
end
end
factory :impression do
impressionable factory: :post
request_hash {Faker::Lorem.characters(10)}
session_hash {Faker::Lorem.characters(10)}
ip_address {Faker::Internet.ip_v4_address}
created_at {Faker::Time.between(DateTime.now - 1, DateTime.now)}
end
end
Photo by Mike Steele