Skip to content

Instantly share code, notes, and snippets.

@revans
Created September 24, 2012 22:08
Show Gist options
  • Save revans/3778741 to your computer and use it in GitHub Desktop.
Save revans/3778741 to your computer and use it in GitHub Desktop.
Yockeries - Factories and Mocks from YAML
# Yockeries - Yaml + Mocks + Factories(easy way to create them)
#
# Long ago there was an uprising against YAML fixtures in the rails world. Some
# people replaced them with things like FactoryGirl, Machinist, Fabrication, and a
# bunch of others.
#
# However, YAML is still the simpliest thing that works, because it comes with
# Ruby. When you load in a yaml file with YAML.load_file, the yaml data is
# converted into a hash, which again is simple to use and test. You can take
# that hash and create a new object with it: Person.new(yaml_converted_hash),
# you can use it to create a stand-in double/mock:
# OpenStruct.new(yaml_converted_hash).
#
# What I've done with "Yockeries" is to make that a tiny bit simplier with a
# small amount of code.
#
# Yockeries gives a convienent yaml loader (smart enough to know if you are
# using rspec, minitest, or testunit) to load an entire fixture file into a hash
# and then use the +get+ method to select which yaml object you want to work
# with.
#
# There is also a method +mock_for+ that will create an OpenStruct object where
# you can create a very simple test double/mock.
# YAML File (people.yaml)
#
# robert:
# name: Robert Evans
# email: robert@example.com
# username: revans
# password: 123456
# password_confirmation: 123456
# Examples:
#
# Load a specific User from a YAML File
#
# fixture(:people).get(:robert) # => {:name=>"Robert Evans", :email=>"robert@example.com", :username=>"revans", :password=>123456, :password_confirmation=>123456}
#
#
# Load a mock Object from the YAML file
#
# fixture(:people).mock_for(:robert) # => #<OpenStruct name="Robert Evans", email="robert@example.com", username="revans", password=123456, password_confirmation=123456>
# Real world example with testunit:
#
# assert_difference "Person.count", 1 do
# Person.new(
# fixture(:people).get(:robert)
# )
# end
# Real world example with rspec
#
# expect {
# Person.new(
# fixture(:people).get(:robert)
# ).save
# }.to change { Person.count }.by(1)
require 'yaml'
require 'ostruct'
module Yockeries
class YockHash < Hash
def initialize(hash = {})
@hash = symbolize_keys(hash)
end
def get(name)
@hash[name.to_sym]
end
def mock_for(name)
OpenStruct.new(get(name))
end
private
def symbolize_keys(hash)
case hash
when Array
symbolize_array_keys(hash)
when Hash
symbolize_hash_keys(hash)
else
hash
end
end
def symbolize_array_keys(array)
array.inject([]) do |result, value|
result << case value
when Hash, Array
symbolize_keys(value)
else
value
end
result
end
end
def symbolize_hash_keys(hash)
hash.inject({}) do |result, (key,value)|
nval = case value
when Hash, Array
symbolize_keys(value)
else
value
end
result[key.to_sym] = nval
result
end
end
end
module Loader
def fixture(filename)
dir = File.exists?('test') ? 'test' : 'spec'
::Yockeries::YockHash.new(YAML.load_file("#{dir}/fixtures/#{filename.to_s}.yaml"))
end
end
end
require 'minitest/autorun'
require './yockeries'
module Yockeries
describe YockHash do
let(:hash) do
{ 'user_1' => { 'name' => 'robert', 'email' => 'robert@example.com' },
'user_2' => { 'name' => 'tyler', 'email' => 'ty@example.com' } }
end
subject { YockHash.new(hash) }
it 'symbolizes the keys' do
subject.get('user_1').key?(:name).must_equal true
end
it 'will return the name for user_1' do
subject.get('user_1')[:name].must_equal 'robert'
end
it 'will return the name for user_2' do
subject.get('user_2')[:name].must_equal 'tyler'
end
it 'will return a mock' do
subject.mock_for('user_1').kind_of?(OpenStruct).must_equal true
end
it 'mocks will imitate an object' do
subject.mock_for('user_1').name.must_equal 'robert'
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment