2011-08-15 11 views
29

Czy istnieje biblioteka Java, która może pomóc w tworzeniu instancji klas do testowania? Ten, który bada właściwości fasoli i napełnia ją losowymi danymi.
Po prostu szukam odpowiednika Javy w wersji Object Hydrator dla języka C#.Automatycznie wypełniają prymitywne właściwości losowymi danymi?

+0

Można również spojrzeć na https://github.com/nomemory/mockneat. Jest to biblioteka, której można użyć właśnie w tym celu - do wypełniania obiektów (ważnymi) danymi. –

Odpowiedz

37

Można użyć PoDaM:

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

Jest również w Maven Central, miło. – prasopes

+0

Czy mogę użyć tej biblioteki do generowania losowych parametrów do wywołania metody? –

+0

@Alex, po prostu zapisz POJO, a następnie przeczytaj jego pola – msangel

13

Nie znam struktury, ale napisanie którejś z nich jest dość proste. Złożoność pochodzi od nie-prostych właściwości, czyli asocjacji obiektów. Coś takiego uchwyty podstawy a nawet więcej:

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

Czysto losowe wartości dla typów pierwotnych są trywialne. Bardziej praktyczne zagadnienia obfitują w pola nullable vs. not-nullable, wartości min/max, zakresy dat i wzory łańcuchów. –

+0

@Alistair: Zgoda. Napisałem całkiem zdolny/złożony generator losowych obiektów graficznych, a doświadczenie pozwoliło mi dojść do wniosku, że jest to antypodstawka testowa i należy go w miarę możliwości unikać. –

+0

@RyanStewart dlaczego powinno się go unikać? (Obecnie siedzę, unikając pisania kodu, który utworzy pewną liczbę obiektów domenowych, wszystkie wypełnione losowym datamem, aby przetestować moją warstwę usługową i contoller) – NimChimpsky

1

Do testowania, nasza grupa ma pewne sukcesy z JUnit i Mockito. Oto link to a Mockito answer.

Nie jestem pewien, czy wypełnianie losowymi danymi będzie znaczącym testem. Być może bardziej znaczącym testem byłoby testowanie warunków normalnych, granicznych i błędów.

+3

Tak naprawdę chciałem tego samego narzędzia więcej niż jeden raz (do momentu, w którym sam zacząłem pisać). Warunki normalne/graniczne/błędy są ogólnie dobre dla testów jednostkowych, jednak w przypadku testów wydajności/obciążenia i testów czarnej skrzynki czasami potrzebujesz dużej ilości danych testowych. –

17

Spójrz losowo Fasola:

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

Pozwala wypełnić wykres obiektu Java z danych losowych.

Nadzieja pomaga Pozdrowienia

+0

Po prostu zobacz ten wpis. Jeszcze nie próbowałem, na szybkie spojrzenie, wydawało się, że jest dobre, ponieważ obsługuje hierarchię/zagnieżdżenie obiektów. Dobra robota. Dziękuję za to samo. – Rao

0

Użyłem refleksji i rekurencji tutaj, aby uzyskać wszystkie pola zaludnionych w moim solidnego obiektu, który chciałem zrobić test. Jest to również przy użyciu PODAM, mam nadzieję, że ktoś uzna to za przydatne.

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

A niektóre metody pomocnicze. Kod może nie być idealny, ale działa :).

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

Dzięki, a jeśli istnieje łatwiejszy sposób na wypełnienie wszystkiego, proszę dać mi znać.

5

Można pobrać randomizer dla losowego generowania danych. Ta biblioteka pomaga tworzyć losowe dane z danej klasy Modelu. Sprawdź poniżej przykładowy kod.

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

Ponieważ istnieje wiele wbudowany generator danych jest dostępne za pomocą adnotacji, można również tworzyć niestandardowe dane generator.I proponuję przejść dokumentacji dostarczonej na stronie biblioteki.

+1

Ta biblioteka wydaje się być dobra, ale wymaga modyfikacji fasoli tylko do testów. – Divick

5

https://github.com/benas/random-beans wykonał dla mnie pracę, podczas gdy PoDam nie zadziałał z "płynnymi" seterami, a odpowiedź Ryana Stewarta nie jest kompletna dla kopiowania i wklejania, ponieważ zawiera odniesienia do klas, które nie są odsłonięte! z przypadkowymi ziarnach to tak proste, jak:

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

Gradle:

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

Od wersji 7.0.1 Podam obsługuje domyślnie setery płynów płynnych, a wcześniej możliwe było wywoływanie ich poprzez zdefiniowanie niestandardowej ClassInfoStrategy. – divanov

Powiązane problemy