2011-08-15 104 views
29

是否有一個java庫,可以幫助創建類的實例進行測試?一個檢查bean的屬性並用隨機數據填充的屬性。
我基本上在尋找C#的Object Hydrator的Java等價物。自動使用隨機數據填充原始屬性?

+0

您還可以看看https://github.com/nomemory/mockneat。它可以完全用於這個庫 - 用(有效)數據填充對象。 –

回答

37

你可以使用PoDaM

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

它也在Maven Central,很不錯。 – prasopes

+0

我可以使用此庫爲方法調用生成隨機參數嗎? –

+0

@Alex,只是填充POJO然後閱讀它的字段 – msangel

13

我不知道一個框架,但是自己寫一個框架非常簡單。複雜性來自非簡單屬性,也就是對象關聯。像這樣處理的基本知識,然後一些:

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

原始類型的純粹隨機值很簡單。更多的實際問題圍繞可空與不可空字段,最小/最大值,日期範圍和字符串模式。 –

+0

@Alistair:同意。之前我寫過一個功能非常強大/複雜的隨機對象圖形生成器,經驗讓我得出結論,這是一個測試反模式,應該儘可能避免。 –

+0

@RyanStewart爲什麼要避免它? (我目前正在圍繞避免編寫將創建大量域對象的代碼,所有域都填充了隨機數據,以測試我的服務和控制器層) – NimChimpsky

1

爲了進行測試,我們的團隊已經取得了一些成功的JUnit和的Mockito。這是一個link to a Mockito answer

我不確定填充隨機數據是否是一個有意義的測試。也許更有意義的測試是測試正常,邊界和錯誤條件。

+3

我實際上已經不止一次地希望得到一個類似的工具(直到我開始自己寫一個)。正常/邊界/錯誤條件通常適用於單元測試,但是,對於性能/負載測試和黑盒測試,您有時需要大量的測試數據。 –

17

在隨機豆類看看:

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

它可以讓你來填充隨機數據的Java對象圖。

希望它可以幫助 問候

+0

只是碰巧看到這個職位。還沒有嘗試過,快速瀏覽,似乎是好的,因爲它支持層次結構/嵌套對象。工作很好。謝謝你的一樣。 – Rao

0

我已經使用反射和遞歸在這裏得到填充在我希望得到我的測試對象強勁各個領域。這是使用PODAM以及我希望有人會發現這有用。

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

還有一些輔助方法。代碼可能不完美,但工作:)。

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

謝謝,如果有更簡單的方法來填充所有內容,請讓我知道。

5

您可以結算使用randomizer進行隨機數據生成。此庫有助於從給定Model類創建隨機數據。請參閱下面的示例代碼。

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

由於有很多是使用註解訪問,您也可以創建自定義數據generator.I建議你去通過提供的庫頁的文檔,內置的數據發生器。

+1

這個庫看起來不錯,只是它需要修改Beans才用於測試。 – Divick

5

https://github.com/benas/random-beans爲我完成了這項工作,而PoDam以「流利」的設置者失敗,並且由Ryan Stewart做出的回答並不完整,因爲沒有公開類的引用! 採用隨機豆子很容易,因爲:

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

搖籃:

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

自7.0.1版本開始,Podam默認支持流利設置器,在此之前可以通過定義自定義ClassInfoStrategy來調用它們。 – divanov