Fill primitive properties with random data automatically? [closed]
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Improve this questionOriginal close reason(s) were not resolved
Is there a java library that would help with creating instances of classes for testing? One that examines the properties of a bean and fills it with random data.
I'm basically looking for Java equivalent of Object Hydrator for C#.You could use PoDaM:
PodamFactory factory = new PodamFactoryImpl();
Pojo myPojo = factory.manufacturePojo(Pojo.class);
Take a look at Easy Random.
It allows you to populate a Java Object graph with random data.
Hope it helps.
I don't know of a framework, but it's pretty simple to write one of those yourself. The complexity comes in non-simple properties, aka object associations. Something like this handles the basics and then some:
public static void randomlyPopulateFields(Object object) {
new RandomValueFieldPopulator().populate(object);
}
public static class RandomValueFieldPopulator {
public void populate(Object object) {
ReflectionUtils.doWithFields(object.getClass(), new RandomValueFieldSetterCallback(object));
}
private static class RandomValueFieldSetterCallback implements FieldCallback {
private Object targetObject;
public RandomValueFieldSetterCallback(Object targetObject) {
this.targetObject = targetObject;
}
@Override
public void doWith(Field field) throws IllegalAccessException {
Class<?> fieldType = field.getType();
if (!Modifier.isFinal(field.getModifiers())) {
Object value = generateRandomValue(fieldType, new WarnOnCantGenerateValueHandler(field));
if (!value.equals(UNGENERATED_VALUE_MARKER)) {
ReflectionUtils.makeAccessible(field);
field.set(targetObject, value);
}
}
}
}
}
public static Object generateRandomValue(Class<?> fieldType, CantGenerateValueHandler cantGenerateValueHandler) {
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis() - random.nextInt(DATE_WINDOW_MILLIS));
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else if (fieldType.equals(Integer.TYPE)) {
return random.nextInt();
} else if (fieldType.equals(Long.TYPE)) {
return random.nextInt();
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else {
return cantGenerateValueHandler.handle();
}
}
https://github.com/benas/random-beans did the work for me, while PoDam failed with "fluent" setters and answer by Ryan Stewart is not complete for copy-paste as has references to classes that are not exposed! With random-beans it's as easy as:
Auction auction = EnhancedRandom.random(Auction.class);
Gradle:
testCompile ('io.github.benas:random-beans:3.4.0')
You can checkout randomizer for random data generation.This library helps to create random data from given Model class.Checkout below example code.
public class Person {
@FirstName
String mFirstName;
@LastName
String mLastName;
@Number(min = 14,max = 25,decimals = 0)
int age;
@DateValue( from = "01 Jan 1990",to = "31 Dec 2002" , customFormat = "dd MMM yyyy")
String dateOfBirth;
@Email
String mEmailId;
@StreetAddress
public String streetAddress;
@State
public String state;
//Person can have minimum 1 Phone number and maximum 3 phone number
@Phone(country = Phone.Country.INDIA)
@CollectionDescriptor(min = 1,max = 3)
List<String> phones;
}
//Generate random 100 Person(Model Class) object
Generator<Person> generator = new Generator<>(Person.class);
List<Person> persons = generator.generate(100);
As there are many built in data generator is accessible using annotation,You also can build custom data generator.I suggest you to go through documentation provided on library page.
For testing, our group has had some success with JUnit and Mockito. Here is a link to a Mockito answer.
I am not sure if filling with random data will be a meaningful test. Perhaps a more meaningful test would be testing normal, boundary, and error conditions.
I Have used reflection and recursion here to get all fields populated in my robust object that i wanted to get tested. This is Using PODAM as well i hope somebody will find this useful.
public class Populate {
private final PodamFactory podamFactory = new PodamFactoryImpl();
private <P> P getManufacturedPojo(final Class<P> klass) {
return podamFactory.manufacturePojo(klass);
}
private Object populateAllIn(final Class targetClass) throws IllegalAccessException, InstantiationException {
final Object target = targetClass.newInstance();
//Get all fields present on the target class
final Set<Field> allFields = getAllFields(targetClass, Predicates.<Field>alwaysTrue());
//Iterate through fields
for (final Field field : allFields) {
//Set fields to be accessible even when private
field.setAccessible(true);
final Class<?> fieldType = field.getType();
if (fieldType.isEnum() && EnrichmentType.class.isAssignableFrom(fieldType)) {
//handle any enums here if you have any
}
//Check if the field is a collection
if (Collection.class.isAssignableFrom(fieldType)) {
//Get the generic type class of the collection
final Class<?> genericClass = getGenericClass(field);
//Check if the generic type of a list is abstract
if (Modifier.isAbstract(genericClass.getModifiers())) {
//You might want to use any class that extends
//Your abstract class like
final List<Object> list = new ArrayList<>();
list.add(populateAllIn(ClassExtendingAbstract.class));
field.set(target, list);
} else {
final List<Object> list = new ArrayList<>();
list.add(populateAllIn(genericClass));
field.set(target, list);
}
} else if ((isSimpleType(fieldType) || isSimplePrimitiveWrapperType(fieldType)) && !fieldType.isEnum()) {
field.set(target, getManufacturedPojo(fieldType));
} else if (!fieldType.isEnum()) {
field.set(target, populateAllIn(fieldType));
}
}
return target;
}
And some helper methods. Code might not be perfect but works :).
private Class<?> getGenericClass(final Field field) {
final ParameterizedType collectionType = (ParameterizedType) field.getGenericType();
return (Class<?>) collectionType.getActualTypeArguments()[0];
}
private boolean isSimpleType(final Class<?> fieldType) {
return fieldType.isPrimitive()
|| fieldType.isEnum()
|| String.class.isAssignableFrom(fieldType)
|| Date.class.isAssignableFrom(fieldType);
}
private boolean isSimplePrimitiveWrapperType(final Class<?> fieldType) {
return Integer.class.isAssignableFrom(fieldType)
|| Boolean.class.isAssignableFrom(fieldType)
|| Character.class.isAssignableFrom(fieldType)
|| Long.class.isAssignableFrom(fieldType)
|| Short.class.isAssignableFrom(fieldType)
|| Double.class.isAssignableFrom(fieldType)
|| Float.class.isAssignableFrom(fieldType)
|| Byte.class.isAssignableFrom(fieldType);
}
Thanks, and if there a easier way to populate everything please let me know.
精彩评论