Use a factory's sequence to generate unique phone numbers
Asked Answered
T

4

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!

Themistocles answered 13/9, 2013 at 20:28 Comment(0)
T
7

Try using a lambda with a random 10 digit number:

phone_number { rand(10**9..10**10) } 
Tongue answered 15/9, 2013 at 15:44 Comment(1)
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.Masseuse
S
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) }
Schmitt answered 13/9, 2013 at 20:34 Comment(12)
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 (rubydoc.info/github/thoughtbot/shoulda-matchers/master/Shoulda/…)Valse
Thanks @Valse 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.Schmitt
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?Themistocles
can you paste some code that you have in your model/user_spec? perhaps gist itSchmitt
Sure thing. I should note that adding the uniqueness validation actually causes all of my tests to fail now. Here you go: gist.github.com/dougiebuckets/6556159Themistocles
Failure/Error: it { should validate_uniqueness_of(:phone_number) } NoMethodError: undefined method `first' for String:ClassThemistocles
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?Schmitt
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: gist.github.com/dougiebuckets/6556518 I really appreciate your helpThemistocles
try moving the sequence outside of the factory :user block like I updated in my answer aboveSchmitt
Thanks. Tried that and am still getting that bizarre 'undefined method `first' for String:Class'Themistocles
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 gist.github.com/gotva/6565446Valse
If you care about the length of a phone number this solution won't work when the sequence number gets beyond single digitsCarping
I
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
Innutrition answered 6/7, 2017 at 15:10 Comment(0)
I
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
Incrustation answered 21/4, 2014 at 1:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.