user2361174
user2361174

Reputation: 1942

Rails uniqueness validation test failing

I'm starting out with Rails 4.2, and I'm try to test uniqueness for the Item models I'm making, I ran this code:

item.rb:

class Item < ActiveRecord::Base
    attr_accessor :name
    validates :name, uniqueness: true #, other validations...
end

item_test.rb:

require 'test_helper'

class ItemTest < ActiveSupport::TestCase

    def setup
        @item = Item.new(name: "Example Item")
    end

    test "name should be unique" do
        duplicate_item = @item.dup
        @item.save
        assert_not duplicate_item.valid?
    end
end

but the test didn't pass, saying that the assert_not line is coming out true when it should be nil or false. I basically got this code from a tutorial but cannot figure out why it's not passing. Any help?

Edit: I found the solution, by not defining the other members (specifically :price ) of @item that I defined in the setup action, the test passed. However now I don't know how to make it pass with the the :price member. Below is the full implementation of item.rb & item_test.rb.

item.rb:

class Item < ActiveRecord::Base
    attr_accessor :name, :description, :price
    validates :name, presence: true, uniqueness: true, length: { maximum: 100 }
    validates :description, presence: true,
        length: { maximum: 1000 }
    VALID_PRICE_REGEX = /\A\d+(?:\.\d{0,2})?\z/
    validates :price, presence: true,
        :format => { with: VALID_PRICE_REGEX },
        :numericality => {:greater_than => 0}
end 

item_test.rb:

require 'test_helper'

class ItemTest < ActiveSupport::TestCase

    def setup
        @item = Item.new(name: "Example Item", description: "Some kind of item.", price: 1.00)
    end

    test "name should be unique" do
        duplicate_item = @item.dup
        @item.save
        assert_not duplicate_item.valid?
    end
end

Upvotes: 3

Views: 3979

Answers (4)

user2361174
user2361174

Reputation: 1942

I fixed it, I got rid of the attr_accessor line, the test was then able to access the attributes and was able to detect the duplication.

Upvotes: 0

SteveTurczyn
SteveTurczyn

Reputation: 36880

You've identified at least some of the problem in your edit.

The problem isn't that you're using Item.new instead of Item.create the problem is that when you do @item.save the @item record isn't being saved because it has other validation issues.

You could try...

@item.save(validate: false)

... which will force @item to be written to the database, but the test doesn't really determine why the duplicate_item record is invalid.

Better might be to test that you have an error relating to name...

require 'test_helper'

class ItemTest < ActiveSupport::TestCase

  def setup
    @item = Item.new(name: "Example Item")
  end

  test "name should be unique" do
    duplicate_item = @item.dup
    @item.save(validate: false)
    duplicate_item.valid? # need this to populate errors
    assert duplicate_item.errors
    assert duplicate_item.errors[:name]
  end
end

Upvotes: 3

Prakash Murthy
Prakash Murthy

Reputation: 13077

Almaron's answer above is correct and should be the accepted answer.

I am adding this answer to elaborate on it.

The test would be as follows:

require 'test_helper'

class ItemTest < ActiveSupport::TestCase

  def setup
    @item = Item.create(name: "Example Item")
  end

  test "name should be unique" do
    duplicate_item = @item.dup
    assert_not duplicate_item.valid?
  end
end

Note: duplicate_item need not be saved before validating it.

Upvotes: 5

Almaron
Almaron

Reputation: 4147

The uniqueness validation is performed against the records already existing in the database. And your Item.new(name: "Example Item") is not in the database untill it is saved. So if you use Item.create(name: "Example Item") instead, the test should pass.

Upvotes: 4

Related Questions