Отвратительней поддельных цветов может быть лишь поддельное оружие.

Вера Камша

Введение

Мне часто приходится генерировать тестовые данные, либо для тестов, либо во время работы для заполнения базы данных. Такая работа является рутинной, к тому же тяжело руками сгенерировать правдоподобные и не повторяющиеся данные, которые были бы осмысленными.

Огромный пласт моих проблем ушел, когда я открыл для себя Bogus, это библиотека для генерирования правдоподобных фейковых данных, которые можно использовать в тестах, для инициализации базы данных или в любом другом месте, где нужны какие-то фейковые данные.

Она поддерживает несколько локализаций, что очень удобно если вы хотите сгенерировать данные на русском или ещё каком-то языке. Давайте рассмотрим как её можно использовать и что из этого выйдет. Сделаем краткий разбор API.

Рассмотрим ближе

Будем использовать следующий тип, для генерации данных:

public enum Genre
{
    Action,
    Classic,
    ComicBook,
    Detective
}

public record Book
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public Guid? AuthorId { get; set; }
    public bool InStock { get; set; }
    public Genre Genre { get; set; }
    public decimal Price { get; set; }
}

Для того, чтобы генерировать данные, существует класс Faker, он имеет generic версию, будем использовать именное её.

var authors = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), };

var faker = new Faker<Book>("en")
    .UseSeed(100)
    .RuleFor(book => book.Id, f => f.Random.Guid())
    .RuleFor(book => book.Name, f => f.Random.Word())
    .RuleFor(book => book.AuthorId, f => f.PickRandom(authors).OrNull(f))
    .RuleFor(book => book.InStock, f => f.Random.Bool())
    .RuleFor(book => book.Genre, f => f.PickRandom<Genre>())
    .RuleFor(book => book.Price, f => f.Random.Decimal(5, 150))
    .Rules((f, book) =>
    {
        // Кастомная генерация данных
    });

var books = faker.GenerateForever().Take(10).ToList();

Теперь давайте разбираться.

Конструктор может принимать локализацию, по умолчанию она = “en”, можно указать “ru” или одну из тех, что поддерживается.

Далее делаем вызов UseSeed(100), там может быть любое число, если вам не нужно, чтобы при повторном вызове, возвращались те же данные, то можно пропустить этот вызов. Внутри себя объект создаёт Random и переданное число используется в качестве параметра конструктора, чтобы начать генерацию данных.

Сам API библиотеки очень наглядный. Есть 2 главных способа генерации данных для полей:

  • RuleFor: Генерация данных для конкретного свойства. В первой лямбде необходимо указать свойство, для которого будем генерировать тестовые данные, а вторым параметром мы можем передать значение, которое будет установлено или передать лямбду получающую Randomizer, который предоставляет методы по созданию данных.
  • Rules: Кастомный код, для генерации данных, если к примеру есть какая-то зависимость у свойств, например (bool InActive, DateTime? InActiveDate)

Если нам нужны какие-то связанные AuthorId, то мы можем получить уже существующих авторов, или взять данные из только что сгенерированных.

Метод OrNull, возвращает либо значение на котором был вызван, либо null. Это происходит с определенной вероятность, её можно изменить.

Faker может вернуть, как единственный экземляр объекта, так и бесконечную последовательность IEnumerable<T> GenerateForever().

Итог

Упрощайте жизнь себе и своим коллегам и используйте специализированные tools и библиотеки для генерации данных, чтобы упростить процесс разработки и тестирования.

Ссылки