6

I'm new to TDD, RSpec and factories, and trying to understand how to test that each User's phone number attribute is unique. To do so, I'm trying to use a sequence in my User factory. I'm not having much luck with the following:

FactoryGirl.define do
  factory :user do
    number = 123456789
    sequence(:phone_number) {|n| (number + n).to_s }
  end
end

Any thoughts on the best way to accomplish this? Also, what kind of test would make sense for something like this where ultimately I would want to add the following validation to the user model to make such a test pass?

validates :phone_number, :uniqueness => true

Thanks!

dougiebuckets
  • 2,383
  • 3
  • 27
  • 37

4 Answers4

8

Try using a lambda with a random 10 digit number:

phone_number { rand(10**9..10**10) } 
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
candiman
  • 162
  • 1
  • 4
  • 5
    This will not ensure you get a unique phone number. Granted its highly unlikely, but in any case, its better practice to be sure by using sequences as drekyau pointed out. – Sean Oct 13 '16 at 19:47
5

Try this:

FactoryGirl.define do
  sequence :phone_number do |n|
     "123456789#{n}"
  end

  factory :user do
    phone_number
  end
end

and in order to test your validation use this in your user_spec

it { should validate_uniqueness_of(:phone_number) }
derekyau
  • 2,936
  • 1
  • 15
  • 14
  • 1. `validate_uniqueness_of` this is method of gem 'shoulda-matchers'. 2. remember that you should create a record in this table before such test (http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/Shoulda/Matchers/ActiveModel#validate_uniqueness_of-instance_method) – gotva Sep 13 '13 at 20:37
  • Thanks @gotva totally right that it is a shoulda matcher and that you should make sure you include those. However, you don't need a db record to run that matcher since it just validates that essentially the right lines are in your model. – derekyau Sep 13 '13 at 20:43
  • Thanks guys. I've added 'shoulda-matchers'. Though, when I actually add the validation to the model (i.e. 'validates :phone_number, :uniqueness => true') the test still fails. Any thoughts? – dougiebuckets Sep 13 '13 at 20:54
  • can you paste some code that you have in your model/user_spec? perhaps gist it – derekyau Sep 13 '13 at 21:02
  • Sure thing. I should note that adding the uniqueness validation actually causes all of my tests to fail now. Here you go: https://gist.github.com/dougiebuckets/6556159 – dougiebuckets Sep 13 '13 at 21:13
  • Failure/Error: it { should validate_uniqueness_of(:phone_number) } NoMethodError: undefined method `first' for String:Class – dougiebuckets Sep 13 '13 at 21:32
  • weird... could you 1) make sure shoulda-matchers is installed (restart guard), and also what is causing the 'first' problem? Can I see your factory as well? If you delete everything in the user_spec except for the shoulda matcher, does it work? – derekyau Sep 13 '13 at 21:38
  • I can confirm should-matchers is installed and have restarted guard. Concerning the 'first' issue, no idea? Is that something from shoulda-matcher? If I delete everything except 'it { should validate_uniqueness_of(:phone_number) }' I still get the error. 'Here's the factory: https://gist.github.com/dougiebuckets/6556518 I really appreciate your help – dougiebuckets Sep 13 '13 at 21:50
  • try moving the sequence outside of the factory :user block like I updated in my answer above – derekyau Sep 13 '13 at 21:57
  • Thanks. Tried that and am still getting that bizarre 'undefined method `first' for String:Class' – dougiebuckets Sep 14 '13 at 12:12
  • According to the documentation `shoulda-matchers` tries to create a record in tables `users` without validation `User.new.save(validation => false)` and this can be the source of the problem. I suggest 1. Try to repeat this code (`User.new.save...`) in your console - do you have the same error? 2. try to read the stack of the error in tests - usually it reports about where in your APP the problem is raised. 3. create a record in DB yourself https://gist.github.com/gotva/6565446 – gotva Sep 14 '13 at 20:39
  • If you care about the length of a phone number this solution won't work when the sequence number gets beyond single digits – Toby 1 Kenobi Sep 24 '18 at 06:18
4

To complete @westonplatter answer, in order to start at 0 000 000 000, you can use String#rjust:

FactoryGirl.define do
  factory :user do
    sequence(:phone_number) {|n| n.to_s.rjust(10, '0') }
  end
end

Example:

> 10.times { |n| puts n.to_s.rjust(10, '0') }
0000000000
0000000001
0000000002
0000000003
0000000004
0000000005
0000000006
0000000007
0000000008
0000000009
mdemolin
  • 2,514
  • 1
  • 20
  • 23
0

While the random solution works, you have a small chance of not getting a unique number. I think you should leverage the FactoryGirl sequence.

We can start at, 1,000,000,000 (100-000-000) and increment up. Note: This only gives you 98,999,999,999 unqiue phone numbers, which should be sufficient. If not, you have other issues.

FactoryGirl.define do
  sequence :phone_number do |n|
    num = 1*(10**8) + n
    num.to_s
  end

  factory :user do
    phone_number
  end
end
westonplatter
  • 1,475
  • 2
  • 19
  • 30