random-jpa
random-jpa copied to clipboard
Create random test data for JPA/Hibernate entities.
Random-JPA
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 | 1.5+ | v0.6.6 |
com.github.kuros.random-jpa | 1.8+ | v1.0.4 |
Feature
- 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.
Supported Database
- Microsoft SQL Server
- MySQL
- Oracle
- Postgres
- NONE (You can still use functionality, but the dependency has to provided/maintained manually).
Supported JPA Implementation
- Hibernate (Version - 4.x, 5.x)
- EclipseLink
Usage
In order to use.
Initialize JPAContextFactory
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();
Initialization with Dependencies
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();
Creating RandomGenerators
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);
}
});
Initializing RandomGenerators
final JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
.with(generator)
.generate();
Adding Preconditions
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();
Using JPAContext
Creating Plan
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"));
Modify the creationPlan
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");
Printing the creationPlan
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
Persisting the creationPlan
final ResultMap resultMap = jpaContext.persist(creationPlan);
You can also create and persist plans
final ResultMap resultMap = jpaContext.createAndPersist(
Entity.of(Employee.class, 2).with(Employee_.Country, INDIA),
Entity.of(Person.class).with(Person_.gender, "Male"));
Fetching the persisted objects
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
Printing the Persisted objects
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