New Project to improving tests
juniorjrjl opened this issue · 9 comments
Is your feature request related to a problem? Please describe.
No exactly problem,I have suggest to generate random objects to use in tests. ex.:
I have a User class and I have class who will generate instances with random data in all properties, but insetad of create a class to generate instances, we could use annotation processor to generate this classes.
Describe the solution you'd like
Look at my repository
https://github.com/juniorjrjl/jfaker/
docs.:
https://github.com/juniorjrjl/jfaker/wiki
I create a projetc who using annotation processor to create Bot class, this bot class will generate instances with random data and a data provider is a datafaker, I suggest a new project who will use a datafaker.
feel free to use my code and improve it to create a new project
Introduction
What is a JFaker
JFaker is a lib who use annotation processor to create bot class who create instances of your project class with random data for you worry only to create your test, follow a test example with and without JFaker:
imagine you be testing a class who maps some object to another
code example without JFaker (fixed data)
// configuraçoes da sua classe com sua lib de testes
void mapTest(){
var entity = new UserEntity();
entity.setId(1);
entity.setName("name");
var dto = testClass.toDTO(entity);
//asserções do seu código
}
code example with JFaker (with random data to make your test more dynamic)
// configuraçoes da sua classe com sua lib de testes
void mapTest(){
var entity = UserEntityBot
.builder()
.build();
var dto = testClass.toDTO(entity);
//asserções do seu código
}
The best part about this is who the UserEntityBot class is generated each time you will do a build using a simple configuration
Starting with JFaker
Make a follow steps
1- For use JFaker in your project, just add a follow dependencies:
JFaker use a Datafaker lib in bots for generate random data ( for more informations how Datafaker works here have a link for Datafaker's documentation)
2 - Extends a class net.datafaker.Faker
from Datafaker lib and we will start a configure your bots
//imports
@FakerInfo(
botsConfiguration = {
@AutoFakerBot(
generatedInstance = "br.com.sample.UserEntity",
packageToGenerate = "br.com.sample.bot",
botBuildStrategy = @BotBuildStrategy(
setterStrategy = @SetterStrategy
)
)
}
)
public class MyCustomFaker extends Faker {
}
In a previous code we say to generate a bot for UserEntity class in a package br.com.sample.bot
and the bot will input data using setters class method.
Now you are ready to use your UserEntityBot who will have a code looks like a follow code:
// imports omitidos
public class UserEntityBot extends AbstractBot<UserEntity> {
private MyCustomFaker faker = new MyCustomFaker();
private Supplier<Long> id = () -> (long) faker.number().positive();
private Supplier<String> name = () -> faker.lorem().word();
public BookModelBot withId(final Supplier<Long> id) {
this.id = id;
return this;
}
public BookModelBot withName(final Supplier<String> name) {
this.name = name;
return this;
}
public BookModel build() {
var userEntity = new br.com.sample.UserEntity();
userEntity.setId(id.get());
userEntity.setName(name.get());
return userEntity;
}
}
Is possible to populate your instance using other strategies (check in a documentation a section where we say about @BotBuildStrategy )
How you looks like our bot allow to define a fixed data for tests where we need some specific information in a class property, for this we use a with methods
All generated bots by defaul extend a class AbstractBot
to provide some methods. A build method without arguments for create a single instance with random data and a overload who receive a long argument and generate a list with X instances, where X is a number input in build argument ( for more informations about AbstractBot
class click )
that is cool! I don't knew about this. But my idea is litle different, this annotation is used in runtime, my project use annotation processor to generate bot class, you don't need annotate model class and "dirty" it, annotation processor will generate a class to build instances and allow you configure providers for each class properties, create extensions for generate your bot and store it in a database ( for exemple).
I thing many things to make project very extendable and flexible, but thank you for space to show it :)
That's great @juniorjrjl , thank you for sharing! What's your intention with JFaker? Do you want to keep it a separate project and use Datafaker as a potential data provider? Or would you consider a tighter integration between the 2? I think we would be open to any kind of approach, and if we should make changes to make JFaker + Datafaker easier, let us know, happy to discuss!
Thanks for sharing this
But my idea is litle different, this annotation is used in runtime, my project use annotation processor to generate bot class, you don't need annotate model class and "dirty" it, annotation processor will generate a class to build instances and allow you configure providers for each class properties, create extensions for generate your bot and store it in a database ( for exemple).
we were thinking about similar approach however we faced a couple of limitations
- How to generate an object with different locale
- How to generate an object with different seed
- How to generate several different objects (one with Japanese locale and seed 1, another with Japanese locale and seed 10, the third one with French locale and seed 10 and the fourth one with French locale and seed 1000)?
How do you solve this with such configuration?
@bodiam I think about integration is good, I believe this suggest have a great potential and could be very interesting to help a create tests were developer write less code to generate object instances and care more about tests's scenary.
@snuyanzin about your questions
1 I my actual code I didn`t think about, but I think it's possible make some changes
// imports omitidos
public class UserEntityBot extends AbstractBot<UserEntity> {
private MyCustomFaker faker = new MyCustomFaker();
private Supplier<Long> id = () -> (long) faker.number().positive();
private Supplier<String> name = () -> faker.lorem().word();
public BookModelBot withId(final Supplier<Long> id) {
this.id = id;
return this;
}
public BookModelBot withName(final Supplier<String> name) {
this.name = name;
return this;
}
public BookModel build() {
var userEntity = new br.com.sample.UserEntity();
userEntity.setId(id.get());
userEntity.setName(name.get());
return userEntity;
}
}
this code is a class example generated by my code, for solve this problem we could change a moment where faker instance is created (instantiate in build method for example) and pass a locale by param
2 - In this code is possible, all generated bots extend a class AbstractBot, but is possible configure bots to use another class, you need create a another class inherits AbstractBot and put in this class a method who returns a bot instance after save it on database, I create a wiki in this repository explain some resources https://github.com/juniorjrjl/jfaker/wiki (sorry if my english is bad in this wiki) and in this topic have a solution of this question https://github.com/juniorjrjl/jfaker/wiki/9---Customize-your-Bots
3 - For this we need think about faker object is instantiate ( like I explain in answer 1)
this code is a first version, We can think about improve it and include more features.
thanks for explanation
i was asking since all 3 cases are now covered by datafaker existing functionality and locale/seed should be just specified via annotation or method call (both are possible)
no need for other changes
Is any action required for this ticket?
i don't think so
i would consider it like FYI