Częstym problemem – szczególnie podczas tworzenia aplikacji typu Proof of Concept jest szybkie generowanie danych testowych.
W mojej aplikacji – CyberHome – chciałem sprawdzić wydajność bibliotek do automatycznego mapowania jednej klasy na drugą, skąd jednak wziąć wystarczająca ilość danych testowych? Jest do tego kilka wartościowych narzędzi.
nBuilder
nBuilder – to bardzo wygodna i prosta w obsłudze biblioteka, niestety nie rozwijana od 2012 roku.
Instalacja:
Install-Package NBuilder
Przykład użycia:
var products = Builder<Person>.CreateListOfSize(10).Build();
Spowoduje utworzenie 10-elementowej listy obiektów klasy Person z wypełnionymi właściwościami.
Polecam lekturę wiki projektu i dokumentu na GitHubie – jest tam dostępne wiele przydatnych przykładów, np. generowanie danych z określonymi wartościami atrybutów:
var products = Builder<Product> .CreateListOfSize(10) .WhereAll() .Have(x => x.PriceBeforeTax = generator.Next(50, 1000)) .Build();
Możemy też generować chierarchie obiektów:
var hierarchySpec = Builder<HierarchySpec<Category>>.CreateNew() .With(x => x.AddMethod = (parent, child) => parent.AddChild(child)) .With(x => x.Depth = 5) .With(x => x.MaximumChildren = 10) .With(x => x.MinimumChildren = 5) .With(x => x.NamingMethod = (cat, title) => cat.Title = "Category " + title) .With(x => x.NumberOfRoots = 10).Build(); Builder<Category>.CreateListOfSize(2500).BuildHierarchy(hierarchySpec);
Podsumowanie:
Podstawowa wadą nBuildera jest losowość generowanych encji oraz niezbyt rozbudowane możliwości konfiguracji.
Do większości zastosowań jednak wystarczy. NBuilder jest szybki, prosty w obsłudze i wygodny.
Faker.js i Bogus
Być może część z Was słyszała o projekcie faker.js (GitHub) umożliwia on generowanie całkiem sensownych, konkretnych danych, a nie – jak nBuilder – przypadkowych.
API umożliwia generowanie wszystkich danych, których najczęściej potrzebujemy, dostępne są następujące kategorie:
- address
- commerce
- company
- date
- finance
- hacker
- helpers
- image
- internet
- lorem
- name
- phone
- random
- system
Jeśli kogoś intrygują niektóre nazwy – zapraszam na stronę projektu celem wypróbowania do czego służą. 🙂
Brian Chavez stworzył .NETowy port do Faker.js o polsko brzmiącej nazwie Bogus (od ang. podrobiony), używa się tego bardzo przyjemnie i szybko:
install-Package Bogus
Na gitHubie jest przejrzysta dokumentacja oraz liczne przykłady.
Poniżej krótka prezentacja kilku możliwości:
var testUsers = new Faker<User>() //Optional: Call for objects that have complex initialization .CustomInstantiator(f => new User(userIds++, f.Random.Replace("###-##-####"))) //Basic rules using built-in generators .RuleFor(u => u.FirstName, f => f.Name.FirstName()) .RuleFor(u => u.LastName, f => f.Name.LastName()) .RuleFor(u => u.Avatar, f => f.Internet.Avatar()) .RuleFor(u => u.UserName, (f, u) => f.Internet.UserName(u.FirstName, u.LastName)) .RuleFor(u => u.Email, (f, u) => f.Internet.Email(u.FirstName, u.LastName)) .RuleFor(u => u.SomethingUnique, f => $"Value {f.UniqueIndex}") //Use an enum outside scope. .RuleFor(u => u.Gender, f => f.PickRandom<Gender>()) //Use a method outside scope. .RuleFor(u => u.CartId, f => Guid.NewGuid()) //Compound property with context, use the first/last name properties .RuleFor(u => u.FullName, (f, u) => u.FirstName + " " + u.LastName) //And composability of a complex collection. .RuleFor(u => u.Orders, f => testOrders.Generate(3).ToList()) //After all rules are applied finish with the following action .FinishWith((f, u) => { Console.WriteLine("User Created! Id={0}", u.Id); }); var user = testUsers.Generate(); Console.WriteLine(user.DumpAsJson());
Bogus umożliwia generowanie danych w rożnych językach, w tym po polsku!
Mamy również gotową klasę Person modelującą większość powszechnych atrybutów osoby – bardzo przydatne w testach!
Podsumowanie:
Bogus jest szybki, ciągle rozwijany i ma duże możliwości konfiguracji; dodając do tego przejrzystą dokumentację i dobry kontakt z autorem – wyłania się nam bardzo dobry framework do generowanie testowych danych dla naszych aplikacji.
Na koniec krótki przykład z mojego programu:
var persons = new Faker<PersonEntity>() .RuleFor(x => x.Name, f => f.Name.FirstName()) .RuleFor(x => x.Age, f => f.Random.Number(18, 65)) .RuleFor(x => x.Salary, f => f.Finance.Amount(1000, 5000)) .RuleFor(x => x.Office, f => new Office { Description = f.Lorem.Text(), OpeningHours = f.Date.Past() }) .Generate(200000).ToList();
Generowanie 200 000 instancji klasy trwa mniej niż 7 sec!
Artykuł w ukazuje się w ramach projektu CyberHome tworzonego w ramach akcji DajSięPoznać.
Ja jestem uzależniony od Autofixture, polecam! 🙂