Created
April 18, 2016 13:43
-
-
Save ignar/b8d10566f47b5ac081985bf4f3c69fd2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
# TODO: there are a lot of code that duplicates, move it to helpers | |
RSpec.describe FactoryBoy do | |
User = Struct.new(:name, :admin) | |
Building = Struct.new(:address) | |
before(:each) do | |
FactoryBoy.reset | |
end | |
describe '.register' do | |
it 'is empty in the beginning' do | |
expect(described_class.register).to be_kind_of(Hash) | |
expect(described_class.register).to be_empty | |
end | |
end | |
describe '.define_factory' do | |
it 'stores classes' do | |
described_class.define_factory(User) | |
expect(described_class.register).to include(User) | |
end | |
it 'saves only uniq class names' do | |
described_class.define_factory(User) | |
described_class.define_factory(User) | |
expect(described_class.register.length).to eq(1) | |
end | |
it 'accepts default values' do | |
described_class.define_factory(User) do | |
name 'Alex' | |
end | |
object = described_class.build(User) | |
expect(object.name).to eq('Alex') | |
end | |
context 'symbol instead of class' do | |
it 'accepts symbol' do | |
described_class.define_factory(:user) | |
object = described_class.build(:user, name: 'Alex') | |
expect(object.name).to eq('Alex') | |
end | |
end | |
# TODO: raname it | |
context 'given different class' do | |
it 'creates object' do | |
described_class.define_factory(:admin, class: User) do | |
name 'Artem' | |
admin true | |
end | |
object = described_class.build(:admin) | |
expect(object).to be_kind_of(User) | |
expect(object.admin).to be_truthy | |
expect(object.name).to eq('Artem') | |
end | |
end | |
end | |
describe '.build' do | |
context 'unknown factory' do | |
it 'raises exception' do | |
expect { | |
described_class.build(Building) | |
}.to raise_error(described_class::NoFactoryDefined) | |
end | |
end | |
context 'without arguments' do | |
it 'creates instance of User' do | |
# TODO: move to helper | |
described_class.define_factory(User) | |
expect(described_class.build(User)).to be_kind_of(User) | |
end | |
end | |
context 'with arguments' do | |
it 'creates instance with params' do | |
described_class.define_factory(User) | |
object = described_class.build(User, name: 'Alex') | |
expect(object.name).to eq('Alex') | |
end | |
end | |
end | |
# TODO: move to separete file | |
describe FactoryBoy::ClassBuilder do | |
context 'given class' do | |
it 'creates instance' do | |
builder = described_class.new(User) | |
expect(builder.build.to_s).to eq('User') | |
end | |
end | |
context 'given symbol' do | |
it 'creates instance' do | |
builder = described_class.new(:user) | |
expect(builder.build.to_s).to eq('User') | |
end | |
end | |
context 'given symbol with class' do | |
it 'creates instance' do | |
builder = described_class.new(:admin, class: User) | |
expect(builder.build.to_s).to eq('User') | |
end | |
end | |
end | |
# TODO: move to separete file | |
describe FactoryBoy::Builder do | |
describe '.initialize' do | |
context 'without block' do | |
it 'creates proper builder' do | |
builder = described_class.new(User) | |
expect(builder.factory_key).to be(User) | |
end | |
end | |
context 'with block' do | |
it 'creates proper builder' do | |
builder = described_class.new(User) do | |
name 'Alex' | |
end | |
expect(builder.factory_key).to be(User) | |
end | |
end | |
end | |
describe 'prepare' do | |
it 'builds hash with arguments' do | |
builder = described_class.new(User) do | |
name 'Alex' | |
end | |
builder.prepare | |
expect(builder.hash).to eq(name: 'Alex') | |
end | |
end | |
describe 'builder' do | |
context 'no block' do | |
subject { described_class.new(User) } | |
it 'builds instnace' do | |
# TODO: move prepare to before each | |
subject.prepare | |
object = subject.build | |
expect(object).to be_kind_of(User) | |
end | |
end | |
context 'with block' do | |
subject do | |
described_class.new(User) do | |
name 'Alex' | |
end | |
end | |
it 'builds instance' do | |
subject.prepare | |
object = subject.build | |
expect(object.name).to eq('Alex') | |
end | |
end | |
context 'block and arguments' do | |
# FIX: duplication | |
subject do | |
described_class.new(User) do | |
name 'Alex' | |
end | |
end | |
it 'builds instance' do | |
subject.prepare | |
object = subject.build(name: 'Artem') | |
expect(object.name).to eq('Artem') | |
end | |
end | |
end | |
end | |
end | |
class FactoryBoy | |
NoFactoryDefined = Class.new(StandardError) | |
# TODO: move to separete file | |
class Builder | |
attr_reader :factory_key, :hash, :block | |
def initialize(factory_key, opts = {}, &block) | |
@factory_key = factory_key | |
@block = block | |
@opts = opts | |
@hash = {} | |
end | |
# TODO: remove this method | |
def prepare | |
self.instance_eval(&block) if block | |
end | |
def method_missing(key, *args) | |
# TODO: raise method missing | |
hash[key] = args.first | |
end | |
def build(args = {}) | |
# FIX: move hash.merge and arguments building into separated class. | |
# because of single responsibility | |
arguments = hash.merge(args) | |
builder = ClassBuilder.new(factory_key, @opts) | |
klass = builder.build | |
klass.new(*arguments.values) | |
end | |
end | |
# FIX: refactory and user some kind of strategry/builder pattern | |
# there are a lot of branching and conditions. And it is not the best name | |
# TODO: move to separete file | |
class ClassBuilder | |
attr_reader :klass | |
def initialize(factory_key, opts = {}) | |
if factory_key.kind_of?(Symbol) && !opts.has_key?(:class) | |
@klass = eval(factory_key.to_s.capitalize) | |
elsif factory_key.kind_of?(Symbol) && opts.has_key?(:class) | |
@klass = opts[:class] | |
else | |
@klass = factory_key | |
end | |
end | |
def build | |
klass | |
end | |
end | |
class << self | |
def register | |
@register ||= {} | |
end | |
# TODO: this method was created just for test, and I don't like it, | |
# may be it should be renamed/removed | |
def reset | |
@register = {} | |
end | |
def define_factory(factory_key, opts = {}, &block) | |
return if register.include?(factory_key) | |
builder = Builder.new(factory_key, opts, &block) | |
builder.prepare | |
@register[factory_key] = builder | |
builder | |
end | |
def build(klass, **args) | |
raise NoFactoryDefined unless register.has_key?(klass) | |
builder = register[klass] | |
builder.build(args) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment