Creating a sequential date range with Factory Girl

513 views
Skip to first unread message

Megan Byrne

unread,
Aug 18, 2014, 2:22:04 PM8/18/14
to sdr...@googlegroups.com
Hello all,

I'm relatively new to testing and this has been tripping me up for a bit.

I'm working in a code base that contains a Calendar Model (only contains a date field) which is used to help find other data from models with an SQL join for relevant date-ranges.

I need to create a FactoryGirl factory which will be about 10 days worth of sequential dates (10 days back from whatever today's date is) so that I can use that to help test a method on another model which needs to join with the Calendar dates in order to find what it needs.

So, the problem is that I cannot seem to figure out how to create a factory that loops through a set range of things.  Using sequence doesn't seem to work with a range and the blocks I've been using are just plain wrong.  Please help.

I've been doing things like:

FactoryGirl.define
  factory
:calander do
    factory
:dates do |d|
     
10.times do
        d
= 10
        date
{d.days.ago}
        d
-= 1
     
end
   
end
 
end
end

but this is clearly wrong...I guess I'm very confused about FactoryGirl in general 

Any help is greatly appreciated,

Megan

Megan Byrne

unread,
Aug 18, 2014, 2:30:18 PM8/18/14
to sdr...@googlegroups.com
just a quick clarification... on the first line of code, what I actually have is: 
FactoryGirl.define do

I just wanted to clarify that I can, at least, start out a factory correctly ;)

Thanks,
Megan

Adam Grant

unread,
Aug 18, 2014, 2:30:42 PM8/18/14
to sdr...@googlegroups.com
I've used factory girl for creating single instances. It can do multiple instances at once:


built_users   = build_list(:user, 25)
created_users = create_list(:user, 25)
But for your use case, I would just create a normal Ruby method that does the creation:

## 
This may not run, just pseudo-coded...
##
def build_calendar_dates(days)
  calendars = []
  days.times do |day|
    calendars << build(:calendar, :date => Date.today() - day)
  end
  calendars
end

Throw that in your test class, or create a separate help module to reuse this elsewhere.

Regards,
Adam



--
--
SD Ruby mailing list
sdr...@googlegroups.com
http://groups.google.com/group/sdruby
---
You received this message because you are subscribed to the Google Groups "SD Ruby" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sdruby+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Adam Grant

unread,
Aug 18, 2014, 2:51:58 PM8/18/14
to sdr...@googlegroups.com

Rob Kaufman

unread,
Aug 18, 2014, 3:02:13 PM8/18/14
to Adam Grant, sdr...@googlegroups.com
You can also use sequences, like so:

sequence :date do |n|
    (n % 10).days.ago
  end
This will go 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1…  You get the picture.  What Adam is saying about using a set up method is also really solid.  The last thing I’d ask is - can you break your test down a little more so that you don’t need quite so much data just to have a single valid data piece to test against?

Best,
Rob

Ben Hughes

unread,
Aug 18, 2014, 3:24:09 PM8/18/14
to SDRuby
Megan,

A factory instance is only and ever one object (though if there is an association, you can use an after(:create) to build out multiple associated objects, yes).

If you just need multiple objects like it sounds like you do, that has to happen outside the context of your factory girl definitions, such as using a method to go through and build them or what not. In which case the factory definition is pretty simple, because your model/field is simple.

Sequences within factory girl can assist in ensuring different instantiated factories have different values in a sequential manner, but that still does not create multiple objects for you (or ensure that any given number of objects you create necessarily starts with a certain value - sequences are incremented any time the factory is created in your test runtime!).

So I would do something like this:

FactoryGirl.define do
  factory :calendar do
    date { 1.day.ago } # Or whatever you want the "default" for this to be if otherwise unspecified
  end
end

Then to get the objects:

(1..10).map {|n| FactoryGirl.build(:calendar, date: n.days.ago) }.reverse

This of course can be wrapped in a helper method for your tests if you're using it enough.




--

Megan Byrne

unread,
Aug 18, 2014, 3:49:33 PM8/18/14
to sdr...@googlegroups.com
Thank you very much to Adam, Ben and Rob,

Your answers each helped me to better understand things I can do when testing.  I ended up going with Ben's approach, which also helped with my confusion over defining a factory as only one object.

As to the complexity of the data structure and breaking the test down more...I wish I could, but I'm working with a code base with a data structure I'm not at liberty (nor experienced enough) to change/make more efficient, and the method that needs to be tested requires all of these things at a minimum.  It does feel overly complicated to me though too...

Again, thanks so much for all of your help!

Megan

On Monday, August 18, 2014 11:22:04 AM UTC-7, Megan Byrne wrote:
Reply all
Reply to author
Forward
0 new messages