It has been always been a challenge to create a test data. This project aims at providing easier mechanism to create test data.
Maven Group Plugin | java version | Latest Version |
---|---|---|
com.github.kuros.random-jpa | 17+ | v2.0.2 |
com.github.kuros.random-jpa | 1.8+ | v1.0.4 |
com.github.kuros.random-jpa | 1.5+ | v0.6.6 |
- Uses table's foreign key relations to maintain creation order dynamically
- Creates in memory creation plan which can be used to modify column values before persist.
- Provides facility to add custom dependency.
- Provides facility to add random generator (both at class level and attribute level).
- You can print the creation plan and persisted object hierarchy and easily access the respective objects by index.
- Microsoft SQL Server
- MySQL
- Oracle
- Postgres
- NONE (You can still use functionality, but the dependency has to provided/maintained manually).
- Hibernate (Version - 4.x, 5.x)
- EclipseLink
In order to use.
JPAContextFactory accepts two parameters Database and EntityManager. I am using MS_SQL_SERVER for demo.
JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
.generate();
Let us say that you want have a custom dependency between Person and Employee tables but you do not have any foreign key relationship between them. We will have create Dependencies for this using javax.persistence.metamodel.Attribute objects. (Here Person_ & Employee_ are SingularAttributes)
final Dependencies dependencies = Dependencies.newInstance();
dependencies.withLink(Link.newLink(Person_.id, Employee_.personId))
JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
.with(dependencies)
.generate();
There are two ways in which you can control the random generation behavior.
- At Class level
- At Attribute level.
Let us say that you want all the dates to be current date. And all the Long/Integer values to be positive between 0-1000
final Generator generator = Generator.newInstance();
generator.addClassGenerator(new RandomClassGenerator() {
@Override
public Collection<Class<?>> getTypes() {
final List<Class<?>> classes = Lists.newArrayList();
classes.add(Date.class);
return classes;
}
@Override
public Object doGenerate(final Class<?> aClass) {
return new Date();
}
});
generator.addClassGenerator(new RandomClassGenerator() {
@Override
public Collection<Class<?>> getTypes() {
final List<Class<?>> classes = Lists.newArrayList();
classes.add(Long.class);
classes.add(Integer.class);
return classes;
}
@Override
public Object doGenerate(final Class<?> aClass) {
return org.apache.commons.lang.RandomUtils.nextInt(1000);
}
});
You can also override random generation for specific attributes, to do that use RandomAttributeGenerator. Let us say that you want all the employee name to start with "Test-" followed by random string.
generator.addAttributeGenerator(new RandomAttributeGenerator() {
@Override
public List<? extends Attribute> getAttributes() {
final List<SingularAttribute> singularAttributes = new ArrayList<SingularAttribute>();
singularAttributes.add(Employee_.state);
return singularAttributes;
}
@Override
public Object doGenerate() {
return "Test-" + RandomStringUtils.randomAlphanumeric(2);
}
});
final JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
.with(generator)
.generate();
There are scenario's where we want to create some schema in advance before creating our table, and this schema doesn't fall under the hierarchy of main table. To handle such scenarios, we can define PreConditions
final JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
.withPreconditions(Before.of(Employee.class)
.create(Entity.of(Department.class), Entity.of(XXX.class)),
Before.of(Person.class)
.create(Entity.of(Y.class), Entity.of(Z.class)))
.generate();
Once JPAContext is initialized, you can use it to create plans and persist them accordingly. Let us say that we want to create two different Employees referring to single Person Or
CreationPlan creationPlan = jpaContext.create(
Entity.of(Employee.class, 2).with(Employee_.Country, INDIA),
Entity.of(Person.class).with(Person_.gender, "Male"));
Let us say that I want to persist these two employees with different name.
creationPlan.set(Employee_.name, "Employee 1");
creationPlan.set(1, Employee_.name, "Employee 2");
You need to provide a printer, which will print the string.
creationPlan.print(new Printer() {
@Override
public void print(final String string) {
System.out.println(string); // you can use logger
}
});
it will print the hierarchy with the index number of the object followed by
└── *ROOT*
└── com.github.kuros.entity.Person|0
├── com.github.kuros.entity.Employee|0
└── com.github.kuros.entity.Employee|1
final ResultMap resultMap = jpaContext.persist(creationPlan);
final ResultMap resultMap = jpaContext.createAndPersist(
Entity.of(Employee.class, 2).with(Employee_.Country, INDIA),
Entity.of(Person.class).with(Person_.gender, "Male"));
Employee emp1 = resultMap.get(Employee.class);
System.out.println(emp1.getName()); // Prints - Employee 1
Employee emp2 = resultMap.get(Employee.class, 1);
System.out.println(emp2.getName()); //Prints - Employee 2
You need to provide a printer, which will print the string.
resultMap.print(new Printer() {
@Override
public void print(final String string) {
System.out.println(string); // you can use logger
}
});
it will print the hierarchy with the index number of the object followed by the primary key of the persisted objects
└── *ROOT*
└── com.github.kuros.entity.Person|0 [personId: 1]
├── com.github.kuros.entity.Employee|0 [employeeId: 1]
└── com.github.kuros.entity.Employee|1 [employeeId: 2]
** Id's might not get printed for all the loaded entities, since some entities are lazily initialized.
For More details please follow Random-JPA Blogls -l