2011-08-15 13 views
29

¿Hay alguna biblioteca de Java que ayude a crear instancias de clases para probar? Uno que examina las propiedades de un frijol y lo llena con datos aleatorios.
Básicamente estoy buscando el equivalente Java de Object Hydrator para C#.¿Completa las propiedades primitivas con datos aleatorios automáticamente?

+0

También puede echar un vistazo a https://github.com/nomemory/mockneat. Es una biblioteca que se puede usar exactamente para esto: para rellenar objetos con datos (válidos). –

Respuesta

37

Usted podría utilizar PoDaM:

PodamFactory factory = new PodamFactoryImpl(); 
Pojo myPojo = factory.manufacturePojo(Pojo.class); 
+0

También está en Maven Central, agradable. – prasopes

+0

¿Puedo usar esta biblioteca para generar parámetros aleatorios para la llamada al método? –

+0

@Alex, solo llene POJO y lea sus campos – msangel

13

No sé de un marco, pero es bastante simple escribir uno de ellos. La complejidad viene en propiedades no simples, también conocidas como asociaciones de objetos. Algo como esto maneja los conceptos básicos y algo más:

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(); 
    } 
} 
+0

Los valores puramente aleatorios para los tipos primitivos son triviales. Abundan las preocupaciones más prácticas en torno a los campos nulable vs no nulable, valores mínimos/máximos, intervalos de fechas y patrones de cadena. –

+0

@Alistair: De acuerdo. He escrito un generador de gráficos de objetos aleatorios bastante capaz/complejo antes, y la experiencia me llevó a concluir que es un antipatrón de prueba y debe evitarse si es posible. –

+0

@RyanStewart ¿por qué debería evitarse? (Actualmente estoy sentado evitando escribir el código que creará una serie de objetos de dominio, todo rellenado con datam aleatorio, para probar mi servicio y las capas del controlador) – NimChimpsky

1

Para las pruebas, nuestro grupo ha tenido cierto éxito con JUnit y Mockito. Aquí hay un link to a Mockito answer.

No estoy seguro si el llenado con datos aleatorios será una prueba significativa. Tal vez una prueba más significativa sería probar condiciones normales, límites y errores.

+3

En realidad, he deseado una herramienta similar más de una vez (hasta el punto en que comencé a escribir una). Las condiciones normales/límite/error son buenas para las pruebas unitarias en general, sin embargo, para pruebas de rendimiento/carga y prueba de caja negra, a veces se necesitan volúmenes sustanciales de datos de prueba. –

17

Tome un vistazo a las habas azar:

https://github.com/benas/random-beans

Se permite rellenar un gráfico de objetos Java con datos aleatorios.

creo que sirve la reflexión y la recursividad Saludos

+0

Acabo de ver esta publicación. Todavía no lo he intentado, con una mirada rápida, parecía ser bueno, ya que admite jerarquía/jerarquización de objetos. Buen trabajo. Gracias por lo mismo – Rao

0

he utilizado aquí para obtener todos los campos poblados en mi robusta objeto que quería hacerse la prueba. Esto también es usar PODAM, espero que alguien lo encuentre útil.

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; 
    } 

Y algunos métodos de ayuda. El código puede no ser perfecto, pero funciona :).

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); 
} 

Gracias, y si hay una manera más fácil de poblar todo, por favor hágamelo saber.

5

Puede obtener randomizer para generar datos aleatoriamente. Esta biblioteca ayuda a crear datos aleatorios a partir de la clase de modelo dada. Consulte el siguiente código de ejemplo.

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);       

Como hay muchos construidos en el generador de datos es accesible mediante anotación, También se puede construir de datos personalizados generator.I que sugieren que pasar por la documentación proporcionada en la página de la biblioteca.

+1

Esta biblioteca parece buena excepto que requiere modificar beans para pruebas. – Divick

5

https://github.com/benas/random-beans hizo el trabajo por mí, mientras que PoDam falló con setters "fluidos" y la respuesta de Ryan Stewart no está completa para copiar y pegar ya que tiene referencias a clases que no están expuestas. Con azar en grano es tan fácil como:

Auction auction = EnhancedRandom.random(Auction.class); 

Gradle:

testCompile ('io.github.benas:random-beans:3.4.0') 
+0

Desde la versión 7.0.1, Podam admite setters con fluidez por defecto y antes de eso era posible llamarlos definiendo una ClassInfoStrategy personalizada. – divanov

Cuestiones relacionadas