Awesome Open Source
Awesome Open Source
Sponsorship

kotlin-faker

Build Status Version Badge RC Version Badge Coverage Status Issues Badge Awesome Kotlin Badge Licence Badge

Generates realistically-looking fake data

fake-logo

ToC

About

Port of a popular ruby faker gem written completely in kotlin. Generates realistically looking fake data such as names, addresses, banking details, and many more, that can be used for testing purposes during development and testing.

Comparison with other jvm-based faker libs

While there are several other libraries out there with similar functionalities, I had several reasons for creating this one:

  • most of the ones I've found are written in java and I wanted to use kotlin
  • none of them has the functionality I needed
  • I didn't feel like forking an existing kotlin-based lib and refactoring the entire codebase, especially with it not being maintained for the past couple of years.

So why use this one instead? I've decided to make a comparison between this lib and the others that have been out there for quite some time.

The benchmarks time is an average execution time of 10 consecutive runs. Each run includes creating a new Faker instance and generating a 1_000_000 values with the function returning a person's full name.

Note: benchmarks for blocoio/faker could not be done due to unexpected exceptions coming from the lib,
benchmarks for moove-it/fakeit could not be done due to android dependencies in the lib

kotlin-faker DiUS/java-faker Devskiller/jfairy blocoio/faker moove-it/fakeit
language kotlin java java java kotlin
number of available providers (address, name, etc.) 165 73 8 21 36
number of available locales 55 47 10 46 44
extra functionality (i.e. randomClassInstance gen)
actively maintained
cli-bot app
benchmarks 5482ms 17529.9ms 15036.5ms NA NA

Usage

Downloading

Latest releases are always available on jcenter.

From v1.4.1 onward releases are also published on maven central.

With gradle

dependencies {
    implementation 'io.github.serpro69:kotlin-faker:$version'
}

With maven

<dependencies>
    <dependency>
        <groupId>io.github.serpro69</groupId>
        <artifactId>kotlin-faker</artifactId>
        <version>${version}</version>
    </dependency>
</dependencies>

Using release candidate versions

Release candidates contain the newest functionality before next version gets released and can be downloaded by adding the following repo:

Gradle:

repositories {
    maven {
      url 'https://dl.bintray.com/serpro69/maven-release-candidates/'
    }
}

Maven:

<repositories>
    <repository>
        <id>serpro69-maven</id>
        <url>https://dl.bintray.com/serpro69/maven-release-candidates/</url>
        <layout>default</layout>
        <releases>
            <enabled>true</enabled>
        </releases>
    </repository>
</repositories>

Downloading a jar
The jar and pom files can also be found at this link

Generating data

val faker = Faker()

faker.name.firstName() // => Ana
faker.address.city() // => New York

Configuring Faker

Default configuration

If no FakerConfig instance is passed to Faker constructor then default configuration will be used:

  • locale is set to en
  • random is seeded with a pseudo-randomly generated number.
  • uniqueGeneratorRetryLimit is set to 100

Deterministic Random

Faker supports seeding of it's PRNG (pseudo-random number generator) through configuration to provide deterministic output of repeated function invocations.

val fakerConfig = FakerConfig.builder().create {
    random = Random(42)
}

val faker = Faker(fakerConfig)
val city1 = faker.address.city() 
val name1 = faker.name.name()

val otherFaker = Faker(fakerConfig)
val city1 = otherFaker.address.city() 
val name1 = otherFaker.name.name()

city1 == city2 // => true
name1 == name2 // => true

Generating unique values

Faker supports generation of unique values. There are two ways to generate unique values:

Unique values for entire provider

val faker = Faker()
faker.unique.enable(faker::address) // enable generation of unique values for address provider

repeat(10) { faker.address.country() } // will generate unique country each time it's called

To clear the record of unique values that were already generated:

faker.unique.clear(faker::address) // clears used values for address provider

faker.unique.clearAll() // clears used values for all providers

To disable generation of unique values:

faker.unique.disable(faker::address) // disables generation of unique values for address provider and clears all used values

faker.unique.disableAll() // disables generation of unique values for all providers and clears all used values

Unique values for particular functions of a provider

val faker = Faker()

repeat(10) { faker.address.unique.country() } // will generate unique country each time `country()` is prefixed with `unique`

repeat(10) { faker.address.city() } // this will not necessarily be unique (unless `faker.unique.enable(faker::address)` was called previously)

To clear the record of unique values that were already generated:

faker.address.unique.clear("city") // clears used values for `faker.address.unique.city()` function

faker.address.unique.clearAll() // clears used values for all functions of address provider

Configuring retry limit
If the retry count of unique generator exceeds the configured value (defaults to 100) then RetryLimitException will be thrown.

It is possible to re-configure the default value through FakerConfig:

val config = FakerConfig.builder().create {
    uniqueGeneratorRetryLimit = 1000
}

val faker = Faker(config)

Excluding values from generation It is possible to exclude values from being generated with unique generator:

val faker = Faker()
faker.unique.enable(faker::address)

val excludedCountries = listOf(
    "Afghanistan",
    "Albania",
    "Algeria",
    "American Samoa",
    "Andorra",
    "Angola"
)

faker.unique.exclude<Address>("country", excludedCountries)

// in addition to generating unique values 
// this will not generate any of the excluded countries as well
faker.address.country() 

This is only applicable when the whole category, i.e. Address is enabled for unique generation of values.

faker.address.unique.country() // will still generate unique values, but won't consider exclusions if any

Localized dictionary

Faker can be configured to use a localized dictionary file instead of the default en locale.

val fakerConfig = FakerConfig.builder().create {
    locale = "nb-NO"
}

val faker = Faker(fakerConfig)
val city1 = faker.address.city() // => Oslo
Available Locales
List of available locales (clickable):

  • ar
  • bg
  • ca
  • ca-CAT
  • da-DK
  • de
  • de-AT
  • de-CH
  • ee
  • en - default
  • en-AU
  • en-au-ocker
  • en-BORK
  • en-CA
  • en-GB
  • en-IND
  • en-MS
  • en-NEP
  • en-NG
  • en-NZ
  • en-PAK
  • en-SG
  • en-TH
  • en-UG
  • en-US
  • en-ZA
  • es
  • es-MX
  • fa
  • fi-FI
  • fr
  • fr-CA
  • fr-CH
  • he
  • hy
  • id
  • it
  • ja
  • ko
  • lv
  • nb-NO
  • nl
  • no
  • pl
  • pt
  • pt-BR
  • ru
  • sk
  • sv
  • th
  • tr
  • uk
  • vi
  • zh-CN
  • zh-TW

Using a non-default locale will replace the values in some of the providers with the values from localized dictionary.

val fakerConfig = FakerConfig.builder().create {
    locale = "es"
}
val faker = Faker(fakerConfig)
faker.address.city() // => Barcelona

Note that if the localized dictionary file does not contain a category (or a parameter in a category) that is present in the default locale, then non-localized value will be used instead.

val faker = Faker()
faker.gameOfThrones.cities() // => Braavos

val fakerConfig = FakerConfig.builder().create {
    locale = "nb-NO"
}
val localizedFaker = Faker(fakerConfig)
// `game_of_thrones` category is not localized for `nb-NO` locale
localizedFaker.gameOfThrones.cities() // => Braavos

Java interop

Although this lib was created with Kotlin in mind it is still possible to use from a Java-based project thanks to great Kotlin-to-Java interop.

Configuring Faker:

FakerConfig fakerConfig = FakerConfigBuilder.create(FakerConfig.builder(), fromConsumer(builder -> {
    builder.setRandom(new Random(42));
    builder.setLocale("en-AU");
}));

If builder parameter is not called with help of fromConsumer method, then explicit return should be specified:

FakerConfig fakerConfig = FakerConfigBuilder.create(FakerConfig.builder(), builder -> {
    builder.setRandom(new Random(42));
    builder.setLocale("en-AU");
    return Unit.INSTANCE;
});

Calling Faker methods:

new Faker(fakerConfig).getName().firstName(); // => John

CLI

Command line application can be used for a quick lookup of faker functions. See faker-bot README for installation and usage details.

Data Providers

Below is the list of available providers that correspond to the dictionary files found in core/locales/en

Note that not all (although most) of the providers and their functions are implemented at this point. For more details see the particular .md file for each provider below.

List of available providers (clickable):

Generating a random instance of any class

It is possible to generate a random instance of any class with Faker().randomProvider. For example:

class Foo(val a: String)
class Bar(val foo: Foo)
class Baz(val uuid: UUID)

class Test {
    @Test
    fun test() {
        val faker = Faker()

        val foo: Foo = faker.randomProvider.randomClassInstance()
        val bar: Bar = faker.randomProvider.randomClassInstance()
        val baz: Baz = faker.randomProvider.randomClassInstance {
            typeGenerator<UUID> { UUID.randomUUID() }
        }
    }
}

There are the following rules when creating a random instance of a class:

  • The constructor with the least number of arguments is used
  • kotlin.collection.* and kolin.Array types in the constructor are not supported at the moment

Migrating to 1.0

Prior to version 1.0:

  • Faker was a singleton.
  • Random seed was provided through Faker.Config instance.
  • Locale was provided as parameter to init() function.
  • Provider functions were function literals. If invoke() was explicitly specified, then it will have to be removed (See below.)

After version 1.0:

  • Faker is a class.
  • Configuration (rng, locale) is set with FakerConfig class. An instance of FakerConfig can be passed to Faker constructor.
  • Provider functions are no longer function literals. Explicit calls to invoke() will throw compilation error.

For kotlin users

- // prior to version 1.0
- Faker.Config.random = Random(42)
- Faker.init(locale)
- Faker.address.city()
- // or with explicit `invoke()`
- Faker.address.country.invoke()
+ // since version 1.0
+ // locale and random configuration is set with `FakerConfig` class (See Usage in this readme)
+ val faker = Faker(fakerConfig)
+ faker.address.city()
+ // explicit calls to `invoke()` have to be removed
+ faker.address.country()

For java users

Apart from changes to configuring locale and random seed and instantiating Faker through constructor instead of using a singleton instance (see kotlin examples), the main difference for java users is that provider functions are no longer function literals, therefore calls to invoke() operator will have to be removed and getters replaced with function calls.

- // prior to version 1.0
- Faker.init(locale);
- Faker.getAddress().getCity().invoke();
+ // since version 1.0
+ Faker faker = new Faker(fakerConfig);
+ // note `city()` function is called instead of getter 
+ // and no call to `invoke()` operator 
+ faker.getAddress().city();

For developers

Adding a new dictionary (provider)

When adding a new dictionary yml file the following places need to reflect changes:

  • Dictionary.kt - add a new class to CategoryName enum. This is only necessary if the category is not already there.
  • Constants.kt - the new dictionary filename should be added to defaultFileNames property.
  • Faker.kt - add a new faker provider property to Faker class.
  • The provider implementation class should go into provider package.
  • doc - add an .md file for the new provider.
  • reflect-config.json has to be updated to build the native image with graal.
  • And of course unit tests.

Build and Deploy

Build/deploy to bintray and github release processes are automated with travis-ci through usage of git tags.

Bumping versions

Versions need to be bumped manually through a tag with the next release version that has to follow the semver rules, and the tag has to be pushed to origin.

Creating the tag can be either done manually with git tag or by using gradlew tag task.

Pre-releases

To create a new pre-release version (new release candidate) the following can be used: ./gradlew clean tag -Prelease -PnewPreRelease -PbumpComponent={comp}, where comp can be one of the following values: major, minor, or patch.

To bump an existing pre-release to the next version (next release candidate for the same release version) the following can be used: ./gradlew clean tag -Prelease -PpreRelease.

Releases

To promote a pre-release to a release version the following can be used: ./gradlew clean tag -Prelease -PpromoteToRelease,

To create a new release version the following can be used: ./gradlew clean tag -Prelease -PbumpComponent={comp}, where comp can be one of the following values: major, minor, or patch.

Make targets

Alternatively to the above targets from Makefile can be used for the same purposes.

Contributing

Feel free to submit a pull request and/or open a new issue if you would like to contribute.

Thanks

Many thanks to these awesome tools that help us in creating open-source software:
Intellij IDEA YourKit Java profiler

Licence

This code is free to use under the terms of the MIT licence. See LICENCE.md.


Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
java (29,706
kotlin (3,167
testing (881
data (355
testing-tools (188
kotlin-library (130
test-automation (104
faker (40

Find Open Source By Browsing 7,000 Topics Across 59 Categories