Faker: Generate unique values

Created on 28 Aug 2014  路  11Comments  路  Source: faker-ruby/faker

Is there any way to generate guarantee unique value? May be by passing some base unique value.

Now, then I run my tests they sometimes fails because of duplicating names, because Faker::Name.name return random value and sometimes two calls return duplicated values.

I think it may be fixed by passing some my unique value. As I see it:

Faker::Name.name(1) # Always returns value "Jane"
Faker::Name.name(2) # Always returns value "Mary"

Most helpful comment

Using FactoryGirl, In some of my factories I use sequence in combination with Faker:

sequence(:name) { |n| "#{Faker::Company.name}#{n}" }
sequence(:email) { |n| "#{n}#{Faker::Internet.email}" }

Depending on what you want, this might be a good solution.

All 11 comments

Perhaps I'm missing something here but why not just assign the names manually yourself if you need them to be unique and you always want the same values?

Or you could have some function like this in your test helper:

def gen_unique_name(other_name)
  name = Faker::Name.name
  if name == other_name
    gen_unique_name(other_name)
  end
  name
end

@james-ai because, actually, I don't need to use same value, I need unique value each time I call Faker::Name.name. Now it may return same value for 2-3 calls.

Ah, I see, I did miss something.

So you would do something like the following:
We generate two random, distinct integers. Let's say 4, and 7
(1..10).to_a.sample(2)
person1 = Faker::Name.first_name(4)
person2 = Faker::Name.first_name(7)

You could modify fetch to take an index (default nil), but the downside here is that you'd need to add the index argument to each method that you want to be able to call an indexed item.

# Helper for the common approach of grabbing a translation
# with an array of values and selecting one of them.
def fetch(key, index = nil)
   fetched = translate("faker.#{key}")
   if index
     # You'll need to handle the case where the returned object is nil
     fetched = fetched[index] if fetched.class == Array
   else
     fetched = fetched.sample if fetched.respond_to?(:sample)
   end
   if fetched.match(/^\//) and fetched.match(/\/$/) # A regex
    regexify(fetched)
   else
    fetched
  end
end
module Faker
  class Name < Base
    flexible :name

    class << self

      def name
        parse('name.name')
      end

      def first_name(index = nil); fetch('name.first_name', index); end
      def last_name(index = nil);  fetch('name.last_name', index); end
      def prefix;     fetch('name.prefix'); end
      def suffix;     fetch('name.suffix'); end

      # Generate a buzzword-laden job title
      # Wordlist from http://www.bullshitjob.com/title/
      def title; fetch('name.title.descriptor') + ' ' + fetch('name.title.level') + ' ' + fetch('name.title.job'); end

    end
  end
end

For the parse method I guess you can do something similar.

Using FactoryGirl, In some of my factories I use sequence in combination with Faker:

sequence(:name) { |n| "#{Faker::Company.name}#{n}" }
sequence(:email) { |n| "#{n}#{Faker::Internet.email}" }

Depending on what you want, this might be a good solution.

I'm using the same workaround as @Carpetsmoker, but something like the following would be nice:

Faker.unique_mode = true
assert(Faker::Company.name != Faker::Company.name)
Faker.unique_mode = false
assert(
  Faker::Company.name != Faker::Company.name || 
  Faker::Company.name == Faker::Company.name
)

I'm aware that this probably requires quite some effort...

Would it be useful to make/find a gem that can ensure the uniqueness of a non unique data source? To avoid collisions without having ugly numbers.
For example with an email generated by Faker. That would have the cost of storing the existing emails in a Hash but that seems usable.

What do you think?

@tuxayo +1

PHP Faker has a modifier to get unique values (Faker.unique.name):

https://github.com/fzaninotto/Faker#modifiers

Stumbled on this because I'm doing something similar for a rails view where common input values need to return the same name. I realize this issue is pretty old, but figured I'd add this in case it was useful for someone else. I ended up with the following helper wrapped around Faker:

  def unique_name(author)
    hash = Digest::MD5.hexdigest author.to_s
    RequestStore.store[:names] ||= {}
    RequestStore.store[:names][hash] ||= Faker::Name.first_name
  end

RequestStore was there to make sure there is no thread collision with servers like Puma/thin. A hash cache would do fine if that wasn't a concern.

752 has an implementation of unique values.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oyeanuj picture oyeanuj  路  5Comments

huyderman picture huyderman  路  4Comments

mkeiser82 picture mkeiser82  路  3Comments

tejasbubane picture tejasbubane  路  5Comments

ggrillone picture ggrillone  路  6Comments