2013-09-25 64 views
1

我有不同的值對象,每個對象都有一組不同的字段。我怎樣才能用Hamcrest匹配器對這些進行檢查?是否有與公共領域相匹配的Hamcrest麥克風?

public class ValueObjectA { 
     public Integer field1; 
     public String field2; 
     public long filed3; 
     public Object filed4; 
    } 

    public class ValueObjectB { 
     public String field1; 
     public int field2; 
    } 

這是我想做的事:

resultA = getResultA(); 
    ValueObjectA expectedA = new ValueObjectA(); 
    expectedA.field1 = 4; 
    resultB = getResultB(); 
    ValueObjectB expectedB = new ValueObjectB(); 
    expectedB.field1 = "foo"; 
    assertThat(resultA, new ValueObjectMatcher(expectedA)); 
    assertThat(resultB, new ValueObjectMatcher(expectedB)); 

我發現了一個PropertyMatcher但只使用公共干將。我可以寫一些類似的東西,用反射來獲得公共領域。但是有現成的嗎?

+0

請添加代碼,這是非常困難的幫助,而不neing能夠正確地理解手頭的問題... – ppeterka

回答

3

無論如何,我寫了一些基於PropertyMatcher的東西,萬一有人想爲例如。 com.j256.ormlite:

public class ValueObjectMatcher extends TypeSafeDiagnosingMatcher { 
    private final Object expectedVo; 
    private final Set<String> fieldNames; 
    private final List<FieldMatcher> fieldMatchers; 

    public ValueObjectMatcher(final Object expectedVo) { 
     Field[] fieldsToMatch = expectedVo.getClass().getFields(); 
     this.expectedVo = expectedVo; 
     this.fieldNames = fieldNamesFrom(fieldsToMatch); 
     this.fieldMatchers = fieldMatchersFor(expectedVo, fieldsToMatch); 
    } 

    @Override 
    protected boolean matchesSafely(final Object item, final Description mismatchDescription) { 
     return hasAllFields(item, mismatchDescription) && hasMatchingValues(item, mismatchDescription); 
    } 

    @Override 
    public void describeTo(final Description description) { 
     description.appendText("same field values as " + expectedVo.getClass().getSimpleName()) 
       .appendList(" <", ", ", ">", fieldMatchers); 
    } 

    private boolean hasMatchingValues(final Object item, final Description mismatchDescription) { 
     mismatchDescription.appendText(item + " has <"); 
     int mismatchCount = 0; 

     for (FieldMatcher fieldMatcher : fieldMatchers) { 
      if (!fieldMatcher.matches(item)) { 
       if (mismatchCount != 0) { 
        mismatchDescription.appendText(", "); 
       } 
       fieldMatcher.describeMismatch(item, mismatchDescription); 
       mismatchCount++; 
      } 
     } 

     mismatchDescription.appendText(">"); 
     return mismatchCount == 0; 
    } 

    private boolean hasAllFields(final Object item, final Description mismatchDescription) { 
     final Field[] fields = item.getClass().getFields(); 

     final Set<String> itemsFieldNames = fieldNamesFrom(fields); 

     boolean result = true; 

     for (String fieldName : fieldNames) { 
      if (!itemsFieldNames.contains(fieldName)) { 
       result = false; 
       mismatchDescription.appendText("missing field: " + fieldName); 
      } 
     } 

     return result; 
    } 

    private List<FieldMatcher> fieldMatchersFor(final Object expectedVo, final Field[] fields) { 
     List<FieldMatcher> result = new ArrayList<FieldMatcher>(fields.length); 
     try { 
      for (Field field : fields) { 
       result.add(new FieldMatcher(field, expectedVo)); 
      } 
     } 
     catch (NoSuchFieldException e) { 
      throw new IllegalStateException("Programmer exception, pls replace programmer: " + 
              "field list doesn't match with the fields of the provided expectedVo", e); 
     } 
     catch (IllegalAccessException e) { 
      throw new IllegalStateException("Programmer exception, pls replace programmer: " + 
              "field list doesn't match with the fields of the provided expectedVo", e); 
     } 
     return result; 
    } 

    private Set<String> fieldNamesFrom(final Field[] fieldsToMatch) { 
     HashSet<String> result = new HashSet<String>(); 
     for (Field field : fieldsToMatch) { 
      result.add(field.getName()); 
     } 
     return result; 
    } 

    public class FieldMatcher extends DiagnosingMatcher<Object> { 

     private final Object expectedFieldValue; 
     private final String fieldName; 

     private FieldMatcher(Field field, Object expectedVo) throws NoSuchFieldException, IllegalAccessException { 
      this.fieldName = field.getName(); 
      this.expectedFieldValue = expectedVo.getClass().getField(fieldName).get(expectedVo); 
     } 

     @Override 
     protected boolean matches(final Object item, final Description mismatchDescription) { 
      try { 
       final Field fieldItem = item.getClass().getField(fieldName); 
       final Object fieldObjectItem = fieldItem.get(item); 

       if (fieldObjectItem == null) { 
        if (expectedFieldValue != null) { 
         mismatchDescription.appendText(fieldName + ": " + fieldObjectItem); 
        } 
       } else if (!fieldObjectItem.equals(expectedFieldValue)) { 
        mismatchDescription.appendText(fieldName + ": " + fieldObjectItem); 
       } 
      } 
      catch (IllegalAccessException e) { 
       mismatchDescription.appendText(fieldName + " is inaccessible"); 
       e.printStackTrace(); 
      } 
      catch (NoSuchFieldException e) { 
       mismatchDescription.appendText(fieldName + " doesn't exist"); 
       e.printStackTrace(); 
      } 

      return false; 
     } 

     @Override 
     public void describeTo(final Description description) { 
      description.appendText(fieldName + ": " + expectedFieldValue); 
     } 
    } 
} 
4

您可以使用我們最近開放源代碼的庫來做到這一點。它的工作方式與PropertyMatcher類似,但是設計用於執行深度對象圖。結果是它在公共領域「正常工作」。

shazamcrest在github

+0

聽起來不錯。雖然在我的情況下,它可能有點矯枉過正,因爲我只有平面對象進行比較(所以沒有複雜的對象作爲成員)。不管怎樣,以後你的lib會很有用。 –