Factory Girl Alternative

Hi All,

Shameless plug here, but just released my first gem which is a simple
factory plugin a la Factory Girl, but which IMHO gives you much more
control of your factory logic, check it out if interested:

Github: GitHub - ginty/cranky: A simple yet powerful test factory framework that makes it very easy to define your own factories.

Blog: http://www.hyperdecade.com/2010/05/26/cranky-at-factory-girl

Ginty wrote:

Hi All,

Shameless plug here, but just released my first gem which is a simple
factory plugin a la Factory Girl, but which IMHO gives you much more
control of your factory logic, check it out if interested:

Github: GitHub - ginty/cranky: A simple yet powerful test factory framework that makes it very easy to define your own factories.

Blog: http://www.hyperdecade.com/2010/05/26/cranky-at-factory-girl

Interesting. What distinguishes this from Machinist/Fixjour/Fixture
Replacement?

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

There are many factories, but this one is mine…admittedly that
could be it to some extent!

To me the benefits are:

It is extremely light, which means it ain’t gonna break on you when
other components of your test environment change.

No need to pass any blocks about as arguments (I really hate that, but
that could just be me).

The syntax could not be simpler and less obtrusive.

It doesn’t provide any magic for dealing with associations, you’re own
your own. This was probably the #1 reason I developed this for myself,
I just never really felt in control of this from the other solutions I
tried (admittedly I haven’t tried all of the ones on your list) and I
feel much happier writing tests when I know now exactly when and how
secondary instances are being generated.

Ginty wrote:

There are many factories, but this one is mine…admittedly that
could be it to some extent!

To me the benefits are:

It is extremely light, which means it ain’t gonna break on you when
other components of your test environment change.

That sounds good.

No need to pass any blocks about as arguments (I really hate that, but
that could just be me).

Er…what’s wrong with blocks? I don’t get the problem, and anyway,
they’re part of idiomatic Ruby…

The syntax could not be simpler and less obtrusive.

Great!

It doesn’t provide any magic for dealing with associations, you’re own
your own. This was probably the #1 reason I developed this for myself,
I just never really felt in control of this from the other solutions I
tried (admittedly I haven’t tried all of the ones on your list) and I
feel much happier writing tests when I know now exactly when and how
secondary instances are being generated.

What’s the point of factories that don’t handle associations? That
seems like a huge disadvantage. Part of the reason that I use factories
is so I can just say Widget.make and get a fully viable Widget object,
complete with required fields and associations. Otherwise, why bother?

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On May 25, 10:08 pm, Marnen Laibow-Koser [email protected] wrote:

No need to pass any blocks about as arguments (I really hate that, but
that could just be me).

Er…what’s wrong with blocks? I don’t get the problem, and anyway,
they’re part of idiomatic Ruby…

Blocks as wrappers, iterators, etc…very nice, blocks as
arguments…meh.

I just never really felt in control of this from the other solutions I
tried (admittedly I haven’t tried all of the ones on your list) and I
feel much happier writing tests when I know now exactly when and how
secondary instances are being generated.

What’s the point of factories that don’t handle associations? That
seems like a huge disadvantage. Part of the reason that I use factories
is so I can just say Widget.make and get a fully viable Widget object,
complete with required fields and associations. Otherwise, why bother?

Agreed not much point to that.
I didn’t say that it doesn’t provide any behind the scenes magic to
handle them. In your factory definition for the widgets association
you would either just call the create method for the other item, or if
you want something more elaborate (all widgets with the exact same
parent for example) your own helper method.

Here’s the example from the README for a user and an address factory,
and how you relate them.

def user

Define attributes via a hash, generate the values any way you want

define :name => “Jimmy”,
# An ‘n’ counter method is available to help make things
unique
:email => “jimmy#{n}@home.com”,
:role => :user,
# Call your own helper methods to wire up your
associations…
:address => default_address
# This would have worked also if you just want any address…

end

Return a default address if it already exists, or call the address

factory to make one

def default_address
@default_address ||= create(:address)
end

Alternatively loose the DSL altogether and define the factory

yourself,

still callable via Factory.build(:address)

def address
a = Address.new
a.street = “192 Broadway”

You can get any caller overrides via the options hash

a.city = options[:city] || “New York”
a # Only rule is the method must return the generated object
end

end

Anyway if you want any more info check out

it’s well documented.

On May 25, 10:08 pm, Marnen Laibow-Koser [email protected] wrote:

No need to pass any blocks about as arguments (I really hate that, but
that could just be me).

Er…what’s wrong with blocks? I don’t get the problem, and anyway,
they’re part of idiomatic Ruby…

Blocks as wrappers, iterators, etc…very nice, blocks as arguments
to your own methods…meh, blocks as arguments to black box
methods…not really for me.

I just never really felt in control of this from the other solutions I
tried (admittedly I haven’t tried all of the ones on your list) and I
feel much happier writing tests when I know now exactly when and how
secondary instances are being generated.

What’s the point of factories that don’t handle associations? That
seems like a huge disadvantage. Part of the reason that I use factories
is so I can just say Widget.make and get a fully viable Widget object,
complete with required fields and associations. Otherwise, why bother?

Agreed not much point to that.
I didn’t say that it doesn’t handle them, I said that it doesn’t
provide any behind the scenes magic to handle them. In your factory
definition for the widgets association you would either just call your
factory method for the other item, or if you wanted something more
elaborate (all widgets with the exact same parent for example) your
own helper method.

Here’s the example from the README for a user and an address factory
definition, and how you relate them:

def user

Define attributes via a hash, generate the values any way you want

define :name => “Jimmy”,
# An ‘n’ counter method is available for uniqueness
:email => “jimmy#{ n } @home.com”,
:role => :user,
# Call your own association helper methods
:address => default_address
# This would have worked also if you just want any address…
# :address => create(:address)
end

Return a default address if it already exists, or call the address

factory to make one

def default_address
@default_address ||= create(:address)
end

Alternatively loose the DSL altogether and handle all yourself

still callable via Factory.build(:address)

def address
a = Address.new
a.street = “192 Broadway”

You can get any caller overrides via the options hash

a.city = options[:city] || “New York”
a # Only rule is the method must return the generated object
end

Anyway if you want any more info check out

it’s well documented.

Ginty wrote:
Ginty wrote:
[…]

def user

Define attributes via a hash, generate the values any way you want

define :name => “Jimmy”,
# An ‘n’ counter method is available to help make things
unique
:email => “jimmy#{n}@home.com”,

I just realized something else. Because you’re not passing a block
here, your counter method is useless – the variable interpolations in
that string will only be done once, and every call of the factory
thereafter will set email to “[email protected]”. There is no possible
way
for this syntax to work as you intended. The only way to get
this to work is with a block (or with eval, but that’s silly).

In other words, your aversion to blocks as arguments appears to be
breaking your software.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Ginty wrote:

On May 25, 10:08�pm, Marnen Laibow-Koser [email protected] wrote:

No need to pass any blocks about as arguments (I really hate that, but
that could just be me).

Er…what’s wrong with blocks? �I don’t get the problem, and anyway,
they’re part of idiomatic Ruby…

Blocks as wrappers, iterators, etc…very nice, blocks as
arguments…meh.

Uh, no. Passing closures (blocks) as arguments is one feature that
makes Ruby very powerful. You’ll have to do better than “meh” to
explain why you’re choosing not to use a key Ruby feature, at least if
you want people to take you seriously and use your software.

I just never really felt in control of this from the other solutions I
tried (admittedly I haven’t tried all of the ones on your list) and I
feel much happier writing tests when I know now exactly when and how
secondary instances are being generated.

What’s the point of factories that don’t handle associations? �That
seems like a huge disadvantage. �Part of the reason that I use factories
is so I can just say Widget.make and get a fully viable Widget object,
complete with required fields and associations. �Otherwise, why bother?

Agreed not much point to that.
I didn’t say that it doesn’t provide any behind the scenes magic to
handle them. In your factory definition for the widgets association
you would either just call the create method for the other item, or if
you want something more elaborate (all widgets with the exact same
parent for example) your own helper method.

Here’s the example from the README for a user and an address factory,
and how you relate them.

def user

Define attributes via a hash, generate the values any way you want

define :name => “Jimmy”,
# An ‘n’ counter method is available to help make things
unique

Does it work with Faker?

     :email   => "jimmy#{n}@home.com",
     :role    => :user,
     # Call your own helper methods to wire up your

associations…

Does :user just get passed to a helper, or what?

And what didn’t you feel in control of with Machinist or Factory Girl?
Machinist in particular just uses the usual Rails association
mechanisms.

     :address => default_address
     # This would have worked also if you just want any address...

end

Return a default address if it already exists, or call the address

factory to make one

def default_address
@default_address ||= create(:address)
end

Alternatively loose the DSL altogether and define the factory

yourself,

still callable via Factory.build(:address)

def address
a = Address.new
a.street = “192 Broadway”

You can get any caller overrides via the options hash

a.city = options[:city] || “New York”
a # Only rule is the method must return the generated object
end

end

Anyway if you want any more info check out
GitHub - ginty/cranky: A simple yet powerful test factory framework that makes it very easy to define your own factories.
it’s well documented.

I’ll check it out. Based on what you’ve so far said, I doubt that I’ll
replace Machinist with Cranky anytime soon, but I’m always open to
pleasant surprises.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On May 25, 10:51 pm, Marnen Laibow-Koser [email protected] wrote:

arguments…meh.

Uh, no. Passing closures (blocks) as arguments is one feature that
makes Ruby very powerful. You’ll have to do better than “meh” to
explain why you’re choosing not to use a key Ruby feature, at least if
you want people to take you seriously and use your software.

Haha, yeah you’ve probably taken me down a path here I didn’t really
mean to go down.

Marnen says: I didn’t lead you down …

Yeah I know.

Bottom line, this to me is ugly:

u.email {|a| “#{a.first_name}.#{a.last_name}@example.com” }

this is more elegant in it’s simplicity:

:email => “#{first_name}.#{last_name}@example.com

Personal preference.

is so I can just say Widget.make and get a fully viable Widget object,
and how you relate them.

def user

Define attributes via a hash, generate the values any way you want

define :name => “Jimmy”,
# An ‘n’ counter method is available to help make things
unique

Does it work with Faker?

Yeah it’ll work with anything like that, you’re just defining a
regular method, require what you will.

     :email   => "jimmy#[email protected]",
     :role    => :user,
     # Call your own helper methods to wire up your

associations…

Does :user just get passed to a helper, or what?

Good point, maybe a bad example, :user was just the value I pass to my
user.role= method. It doesn’t refer to the user factory, model or
otherwise. Could equally have been :admin or what have you. I’ll
change this in the docs.

And what didn’t you feel in control of with Machinist or Factory Girl?
Machinist in particular just uses the usual Rails association
mechanisms.

For me they are too heavy, too much magic at times (admittedly I am a
Factory Girl guy), I need to think too much about how to create an
association if I want anything other than a randomly generated one,
and ultimately I just don’t like the syntax. The combination of these
things has made me feel that I’ve never really ‘flowed’ with this
aspect of writing my tests for want of a better description.

I said in the blog that Miniskirt was a real revelation to me as it
showed me that these factory helpers don’t need to do much, I don’t
quite understand now why some of them are so big under the hood, but
Miniskirt didn’t hit the syntax aspect for me either.

So Cranky is now my factory of choice, it feels good, very good, and I
don’t think that I have abnormal tastes. So I’ve packaged it up should
others like it to. So if you do cool, if you don’t that’s cool to,
we’re not exactly short of choice here.

Marnen Laibow-Koser wrote::

Ginty wrote:
[…]

def user

Define attributes via a hash, generate the values any way you want

define :name => “Jimmy”,
# An ‘n’ counter method is available to help make things
unique
:email => “jimmy#{n}@home.com”,

I just realized something else. Because you’re not passing a block
here, your counter method is useless – the variable interpolations in
that string will only be done once, and every call of the factory
thereafter will set email to “[email protected]”. There is no possible
way
for this syntax to work as you intended. The only way to get
this to work is with a block (or with eval, but that’s silly).

On third thought, this may not be true either. However, I really don’t
like the need to define a separate user method just to avoid passing
blocks.

In other words, your aversion to blocks as arguments appears to be
breaking your software.

On reflection, perhaps not; but it does appear to be causing lots of
silly contortions in your code.

If you don’t like the core language features, then I suggest (for your
own sanity) that you find a language more compatible with your way of
thinking. Don’t try to make Ruby into (say) PHP, or PHP into Ruby.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Ginty wrote:

On May 25, 10:51�pm, Marnen Laibow-Koser [email protected] wrote:

arguments…meh.

Uh, no. �Passing closures (blocks) as arguments is one feature that
makes Ruby very powerful. �You’ll have to do better than “meh” to
explain why you’re choosing not to use a key Ruby feature, at least if
you want people to take you seriously and use your software.

Haha, yeah you’ve probably taken me down a path here I didn’t really
mean to go down.

Marnen says: I didn’t lead you down …

Yeah I know.

Bottom line, this to me is ugly:

u.email {|a| “#{a.first_name}.#{a.last_name}@example.com” }

this is more elegant in it’s simplicity:

:email => “#{first_name}.#{last_name}@example.com

Personal preference.

For a trivial example like that, sure. But it doesn’t generalize to
anything more complex. Blocks do.

is so I can just say Widget.make and get a fully viable Widget object,
and how you relate them.

def user
� # Define attributes via a hash, generate the values any way you want
� define :name � �=> “Jimmy”,
� � � � �# An ‘n’ counter method is available to help make things
unique

Does it work with Faker?

Yeah it’ll work with anything like that, you’re just defining a
regular method,

I noticed that. On what class?

require what you will.

� � � � �:email � => “jimmy#[email protected]”,
� � � � �:role � �=> :user,
� � � � �# Call your own helper methods to wire up your
associations…

Does :user just get passed to a helper, or what?

Good point, maybe a bad example, :user was just the value I pass to my
user.role= method.

Why on earth would you assign a symbol to what I assume is an
association?

It doesn’t refer to the user factory, model or
otherwise. Could equally have been :admin or what have you. I’ll
change this in the docs.

And what didn’t you feel in control of with Machinist or Factory Girl?
Machinist in particular just uses the usual Rails association
mechanisms.

For me they are too heavy, too much magic at times (admittedly I am a
Factory Girl guy), I need to think too much about how to create an
association if I want anything other than a randomly generated one,
and ultimately I just don’t like the syntax.

I’m not all that fond of FG’s association syntax either. But for
Machinist, it really is just
Post.make.comments.make
or
Comment.make :post => Post.make
just like Rails. If you find that hard to understand, I don’t know what
more I can say.

The combination of these
things has made me feel that I’ve never really ‘flowed’ with this
aspect of writing my tests for want of a better description.

Then try Machinist!

I said in the blog that Miniskirt was a real revelation to me as it
showed me that these factory helpers don’t need to do much, I don’t
quite understand now why some of them are so big under the hood, but
Miniskirt didn’t hit the syntax aspect for me either.

I’ve never even heard of it.

So Cranky is now my factory of choice, it feels good, very good, and I
don’t think that I have abnormal tastes. So I’ve packaged it up should
others like it to. So if you do cool, if you don’t that’s cool to,
we’re not exactly short of choice here.

I think that in your quest for “simplicity”, you’ve wound up with
something that seems to take twice as much work as Machinist to set up a
usable test environment.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On May 25, 11:48 pm, Marnen Laibow-Koser [email protected] wrote:

mean to go down.

and how you relate them.
regular method,
Does :user just get passed to a helper, or what?

Good point, maybe a bad example, :user was just the value I pass to my
user.role= method.

Why on earth would you assign a symbol to what I assume is an
association?

It’s an attribute.

Factory Girl guy), I need to think too much about how to create an

something that seems to take twice as much work as Machinist to set up a
usable test environment.

Yep I think we’re done here, I don’t deny that Machinist may be good,
but I think this is good to.

If this has aroused anyone’s interest please have a look at the README
and judge for yourself.

It couldn’t be simpler to set up test environment.

Mr Marnen!

Been thinking about this today and I see now that my aversion to block
arguments was unfounded.

I think I probably went off on a tangent since I have never really
needed this when defining my factories, and I was always irked that I
was being forced to use a block by my factory of choice (FG) for
something as simple as some string substitutions.

Rather whenever I have needed more complex code to generate the
attribute it has been something that I have needed across multiple
factories where a shared function has been more appropriate, and this I
have often found less than intuitive to achieve with FG.

So this background has been reflected in my choice of syntax here, which
makes it very easy/clear how to share helper methods across factories
and dispenses with the need for a block when a simple string
substitution will do.

That being said I can see now that for the one-off cases being able to
use an anonymous function could come in very handy indeed.

Anyway I’ve added the ability to pass in attributes via a block argument
to my plugin should anyone find it useful. Who knows I may even use it
myself one day.

Cheers.

On May 25, 11:11 pm, Marnen Laibow-Koser [email protected] wrote:

I just realized something else. Because you’re not passing a block
here, your counter method is useless – the variable interpolations in
that string will only be done once, and every call of the factory
thereafter will set email to “[email protected]”. There is no possible
way
for this syntax to work as you intended. The only way to get
this to work is with a block (or with eval, but that’s silly).

On third thought, this may not be true either. However, I really don’t
like the need to define a separate user method just to avoid passing
blocks.

Yes you are indeed talking piffle here.
If you prefer a block to a straight method declaration then this is
not for you, fair enough.

thinking. Don’t try to make Ruby into (say) PHP, or PHP into Ruby.

Nope sorry.