简体   繁体   中英

How to mock a autowired list of Spring beans?

我已经阅读了大量关于如何模拟 Spring 的 bean 及其自动装配字段的文章。但是我找不到关于自动装配的 bean 列表的信息。

具体问题<\/strong>

我有一个名为FormValidatorManager<\/code>的类。这个类循环通过几个实现IFormValidator<\/code>验证器。

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

I finally figured it out...

Sometimes, asking a question can give you a better approach to your problems :p

The problem is I was linking the validators to the list before they were mocked. The validators was then null and no reference could be updated when the MockitAnnotations.initMocks(this) was called.

Moreover, to avoid iterator problems on List , I had to use @Spy instead of @Mock .

Here is the final solution:

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

Adding another answer when dealing with multiple list of beans. Mockito doesnt know anything about the generics it just uses random list provided so in my case something like this happened.

在此处输入图片说明

Which threw the ClassCastException because the bean injection was not perfomed correctly. Expecting SfmcImportRepository but injection was SfmcParser

  @Mock SfmcEmailsCsvFileParser emailParser;
  @Mock SfmcSmsCsvFileParser smsParser;
  @Mock SfmcSmsRepository smsRepository;
  @Mock SfmcEmailRepository emailRepository;

  List<SfmcImportRepository> sfmcImportRepositories = new ArrayList<>();
  List<SfmcParser> sfmcParsers = new ArrayList<>();
  SfmcFtpService service;

  @Before
  public void init() {
    sfmcImportRepositories.add(emailRepository);
    sfmcImportRepositories.add(smsRepository);
    sfmcParsers.add(smsParser);
    sfmcParsers.add(emailParser);
    service = new SfmcFtpService(sfmcImportRepositories, sfmcParsers);
  }

в более позднем MockitoAnnotations метод initMocks - deprecated и более не нужен:

@Mock
private PostgresTxHandler TxHandler1;
@Mock
private S3FileTxHandler TxHandler2;

@Spy
private final List<TxHandler> txHandlers = new ArrayList<>();

@Spy
@InjectMocks
private MyService myService;

//внедрение в список мокированных обработчиков после иниц-ии моков:
@BeforeEach
public void init() {
    lenient().when(TxHandler1.accept(...)).thenReturn(true);
    txHandlers.add(TxHandler1);
    lenient().when(TxHandler2.accept(...)).thenReturn(true);
    txHandlers.add(TxHandler2);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM