2014-04-08 30 views
2

我有一個特定的場景,我只能手動檢查違規情況,稍後在流程中進行檢查。Bean驗證:如何手動創建ConstraintViolation?

我想要做的就是扔了ConstraintViolationException,並提供一個「真正的」 ConstraintViolation object它(當我捕捉到了異常的堆棧,我用的是#{validatedValue}violation.getPropertyPath()參數)。

我怎樣才能創建一個ConstraintViolation我自己沒有框架通過註釋爲我做(我使用Hibernate驗證器)?

代碼示例:

List<String> columnsListForSorting = new ArrayList<String>(service.getColumnsList(domain)); 
Collections.sort(columnsListForSorting); 

String firstFieldToSortBy = this.getTranslatedFieldName(domain.getClass().getCanonicalName(), sortingInfo.getSortedColumn()); 
if (!columnsListForSorting.contains(firstFieldToSortBy)){ 
    throw new ConstraintViolationException(<what here?...>); 
} 

感謝。

+0

到目前爲止,您的測試代碼是什麼? – Morfic

+0

編輯你的問題,添加片段並使用「代碼」按鈕進行格式化,這使得它更容易閱讀:) – Morfic

+0

謝謝,原來的問題已更新。 – odedia

回答

1

在我看來,最簡單的方法是嘲笑你的服務在你的測試中拋出違反約束條件。例如,可以通過擴展類來手動完成,也可以使用模擬框架,例如mockito。我更喜歡嘲笑框架,因爲它們可以簡化很多事情,因爲您不必創建和維護額外的類,也不必處理將它們注入測試對象中。

以作爲的Mockito出發點,你可能會寫類似的東西:

import org.hibernate.exception.ConstraintViolationException; 
import org.mockito.InjectMocks; 
import org.mockito.Mock; 

import static org.mockito.Mockito.when; 


public class MyTest { 
    @Mock /* service mock */ 
    private MyService myService; 

    @InjectMocks /* inject the mocks in the object under test */ 
    private ServiceCaller serviceCaller; 

    @Test 
    public void shouldHandleConstraintViolation() { 
     // make the mock throw the exception when called 
     when(myService.someMethod(...)).thenThrow(new ConstraintViolationException(...)) 

     // get the operation result 
     MyResult result = serviceCaller.doSomeStuffWhichInvokesTheServiceMethodThrowingConstraintViolation(); 

     // verify all went according to plan 
     assertWhatever(result); 
    } 
} 
+1

謝謝你的回答。我想我應該明確表示:這不是用於測試目的,而是生產代碼。 – odedia

+0

然後,除非您不能更改捕獲異常的代碼,否則我看不到違反約束的情況。你更好地拋出一個專用的異常,這使得它更容易理解你想要實現什麼 – Morfic

+0

我想說的是,我沒有看到很多理由拋出一個NullPointerException,如果我的數字應該> 5但實際上它是1,如果你趕上我的漂移 – Morfic

3

這裏幾件事情:

  1. ConstraintViolation是一個接口,所以你可以只實現你自己的版本

  2. Hibernate驗證器使用它自己的內部實現這個inte rface - org.hibernate.validator.internal.engine.ConstraintViolationImpl。這是一個公開課,但由於它在內部包,你不鼓勵直接使用它。但是,您可能會了解實施ConstraintViolation需要什麼。

2

爲什麼我不喜歡Hibernate Validator那個特別的另一個原因。他們使真的很難以編程方式創建一個簡單的違規,當它應該是死的簡單。我確實有測試代碼,我需要創建一個違規,餵養我的嘲笑子系統。

不管怎樣,總之滾動自己的實現違反contraint的 - 這裏是我做的,以創建一個字段的侵犯:

private static final String MESSAGE_TEMPLATE = "{messageTemplate}"; 
private static final String MESSAGE = "message"; 

public static <T, A extends Annotation> ConstraintViolation<T> forField(
    final T rootBean, 
    final Class<T> clazz, 
    final Class<A> annotationClazz, 
    final Object leafBean, 
    final String field, 
    final Object offendingValue) { 

    ConstraintViolation<T> violation = null; 
    try { 
    Field member = clazz.getDeclaredField(field); 
    A annotation = member.getAnnotation(annotationClazz); 
    ConstraintDescriptor<A> descriptor = new ConstraintDescriptorImpl<>(
     new ConstraintHelper(), 
     member, 
     annotation, 
     ElementType.FIELD); 
    Path p = PathImpl.createPathFromString(field); 
    violation = ConstraintViolationImpl.forBeanValidation(
     MESSAGE_TEMPLATE, 
     MESSAGE, 
     clazz, 
     rootBean, 
     leafBean, 
     offendingValue, 
     p, 
     descriptor, 
     ElementType.FIELD); 
    } catch (NoSuchFieldException ignore) {} 
    return violation; 

} 

HTH

+0

_ConstraintViolationImpl.forBeanValidation()_將只從Hibernate Validator **開始工作** 5.x ** –

0

爲什麼在測試中沒有注入Validator並創建一個觸發你想要的驗證錯誤的對象?

Set<ConstraintViolation<T>> res = validator.validate(object);