web-dev-qa-db-ja.com

Spring Beanの自動配線リストをモックする方法は?

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のリストをモックする方法を理解しようとしています。

解決策のアイデアの始まりはありますか?

よろしく

18

私はついにそれを理解しました...

時々、質問することはあなたにあなたの問題へのより良いアプローチを与えることができます: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");
}
24