SpringのBeanとそのオートワイヤーフィールドをモックする方法については、たくさんの記事を読みました。しかし、自動ワイヤードされたBeanのリストについて私が見つけることはできません。
コンクリート問題
FormValidatorManager
というクラスがあります。このクラスは、IFormValidator
を実装するいくつかのバリデーターをループします。
_@Component
public class FormValidatorManager implements IValidatorManager {
@Autowired
private List<IFormValidator> validators;
@Override
public final IFieldError validate(ColumnDTO columnToValidate, String sentValue) {
String loweredColName = columnToValidate.getName().toLowerCase();
IFieldError errorField = new FieldError(loweredColName);
for (IEsmFormValidator validator : validators) {
List<String> errrorsFound = validator.validate(columnToValidate, sentValue);
//les erreurs ne doivent pas être cumulées.
if(CollectionUtils.isNotEmpty(errrorsFound)){
errorField.addErrors(errrorsFound);
break;
}
}
return errorField;
}
}
_
このクラスをテストしたいと思います。しかし、validators
プロパティをモックする方法が見つかりません。
私が試したこと
IFormValidators
はシングルトンなので、これらのBeanのいくつかのインスタンスをモックして、それらが_FormValidatorManager.validators
_に反映されることを期待しましたが、成功しませんでした。
次に、_@Mock
_と注釈が付けられたIFormValidators
のリストを作成しようとしました。 List
を手動で開始することにより、initMocks()
が作成されたリストを挿入することを期待していました。それはまだ成功していませんでした。
これが私の最後の試みです:
_@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring/test-validator-context.xml"})
public class FormValidatorManagerTest {
@Mock
private RegexValidator regexValidator;
@Mock
private FormNotNullValidator notNullValidator;
@Mock
private FormDataTypeValidator dataValidator;
@InjectMocks
private FormValidatorManager validatorManager;
@Mock
private List<IEsmFormValidator> validators = new ArrayList<IEsmFormValidator>();
@Mock
private ColumnDTO columnDTO;
@Before
public void init() {
validators.add(notNullValidator);
validators.add(regexValidator);
validators.add(dataValidator);
MockitoAnnotations.initMocks(this);
Mockito.when(columnDTO.getTitle()).thenReturn("Mock title");
Mockito.when(columnDTO.getName()).thenReturn("Mock name");
}
@Test
public void testNoErrorFound(){
mockValidator(notNullValidator, new ArrayList<String>());
mockValidator(regexValidator, new ArrayList<String>());
mockValidator(dataValidator, new ArrayList<String>());
IFieldError fieldErrors = validatorManager.validate(columnDTO, "Not null value");
Assert.assertEquals(0, fieldErrors.getErrors().size());
verifyNumberOfValidateCalls(regexValidator, Mockito.atMost(1));
verifyNumberOfValidateCalls(dataValidator, Mockito.atMost(1));
verifyNumberOfValidateCalls(notNullValidator, Mockito.atMost(1));
}
private void mockValidator(IFormValidator validator, List<String> listToReturn){
Mockito.when(validator.validate(Mockito.any(ColumnDTO.class), Mockito.anyString())).thenReturn( listToReturn );
}
private void verifyNumberOfValidateCalls(IFormValidator validator, VerificationMode verifMode){
Mockito.verify(validator, verifMode).validate(Mockito.any(ColumnDTO.class), Mockito.anyString());
}
}
_
NPEがIFormValidator.validate()
にスローされますが、これはあざけるでしょう。具体的な実装は呼び出さないでください。
そのクラスに対する私のテストのいくつかは誤検知であり、他のテストは完全に失敗するため、これは本当に悪い動作につながります。
特定の実装をモックする可能性を残しながら、自動接続されたBeanのリストをモックする方法を理解しようとしています。
解決策のアイデアの始まりはありますか?
よろしく
私はついにそれを理解しました...
時々、質問することはあなたにあなたの問題へのより良いアプローチを与えることができます:p
問題は、バリデータがモックされる前にリストにリンクしていたことです。バリデーターはnullになり、MockitAnnotations.initMocks(this)
が呼び出されたときに参照を更新できませんでした。
さらに、List
でのイテレーターの問題を回避するために、@Spy
ではなく@Mock
を使用する必要がありました。
これが最終的な解決策です:
@Mock
private EsmRegexValidator regexValidator;
@Mock
private EsmFormNotNullValidator notNullValidator;
@Mock
private EsmFormDataTypeValidator dataValidator;
@InjectMocks
private EsmFormValidatorManager validatorManager;
@Spy
private List<IEsmFormValidator> validators = new ArrayList<IEsmFormValidator>();
@Mock
private ColumnDTO columnDTO;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
validators.add(notNullValidator);
validators.add(regexValidator);
validators.add(dataValidator);
Mockito.when(columnDTO.getTitle()).thenReturn("Mock title");
Mockito.when(columnDTO.getName()).thenReturn("Mock name");
}