This website uses cookies for analytics and to improve provided services. By choosing I Accept, you consent to our use of them and other tracking technologies according to our Privacy Policy

Turning off auto timestamping for testing in Rails

Suppose that you implemented a functionality that depends on values of created_at or updated_at fields of your models. How do you test it?

If you use fixtures that reside in test/fixture/*.yml files then there is no problem, because the values you set there for created_at and updated_at fields are saved to the database 'as is'. So you can easily have an article created one week ago:

  title: What a great day

However, I don't use fixtures files myself. I feel a bit dirty using them ;) I find fixture replacement tools far more maintainable. Namely, I love thoughtbot's Factory Girl. But here comes the problem. This won't work as expected with Factory Girl:

Factory(:article, :created_at => 1.week.ago, :updated_at => 1.week.ago)

That's because ActiveRecord's automatic timestamping feature sets for created_at and updated_at fields overriding our values. At least that's ActiveRecord's default behavior. Fortunately it can be disabled with:

Article.record_timestamps = false

Chances are that after creating a model with a custom timestamp we'll want to turn automatic timestamping back on. But turning it off and on in many places in your unit tests would be pretty cumbersome. Wouldn't it be cool if you could achieve all of this with a snippet below?

without_timestamping_of Article do
  Factory(:article, :created_at => 1.week.ago, :updated_at => 1.week.ago)

It turns timestamping off, executes the block and turns timestamping back on. I find it clean and dry. Here's the code to place in your test_helper.rb:

# test_helper.rb
class Test::Unit::TestCase # or class ActiveSupport::TestCase in Rails 2.3.x
  def without_timestamping_of(*klasses)
    if block_given?
      klasses.delete_if { |klass| !klass.record_timestamps }
      klasses.each { |klass| klass.record_timestamps = false }
        klasses.each { |klass| klass.record_timestamps = true }

Of course you can turn off timestamping for many models at once:

without_timestamping_of Article, Comment, User do
  Factory(:article, :created_at => 1.week.ago, :updated_at => 1.week.ago)
  Factory(:comment, :created_at =>
  Factory(:user, :updated_at => 5.hours.ago)

Hope you like it. If so, share :)

Pizza Hut Case Study: Introducing Contact-Free Delivery In Less Than 5 Hours
RoR2019 Why Ruby on Rails Is Still a Good Choice in 2020 [UPDATED]
template How to Prepare a Product Spec When Outsourcing Software Development