Nano Hash - криптовалюты, майнинг, программирование

@ReplaceWithMock на @Qualifier

Я использую springockito-annotations 1.0.9 для интеграционного тестирования.

У меня есть следующий контроллер:

@Autowired
    public Controller(
            @Qualifier("passwordService ") PasswordService passwordService ,
            @Qualifier("validator") Validator validator,
            @Qualifier("reportService") ReportService reportService,
            DateCalculator dateCalculator,
            Accessor accessor){
        this.passwordService = passwordService;
        this.validator = validator;
        this.reportService = reportService;
        this.dateCalculator = dateCalculator;
        this.accessor = accessor;
    }

В тесте я собираюсь заменить бины из контекста, используя аннотацию @ReplaceWithMock.

Но, к сожалению, это работает только для зависимостей без аннотации @Qualifier.

А именно, мой тест выглядит так:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(loader = SpringockitoAnnotatedContextLoader.class, classes = {TestContext.class})
public class ControllerTest {

    @Autowired
    @ReplaceWithMock
    private PasswordService passwordService ;
    @Autowired
    @ReplaceWithMock
    private Validator validator;
    @Autowired
    @ReplaceWithMock
    private ReportService reportService;
    @Autowired
    @ReplaceWithMock
    private DateCalculator dateCalculator;
    @Autowired
    @ReplaceWithMock
    private Accessor accessor;

    @Autowired
    private Controller controller;

}

В последнем случае после инициализации контекста только компоненты DateCalculator and Accessor корректно заменяются необходимыми макетами, но другой компонент автоматически подключается как обычный компонент из основного контекста.

После отладки я обнаружил, что QualifierAnnotationAutowireCandidateResolver не может правильно идентифицировать bean-компонент. В строках ниже, начиная с 229:

RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());

Spring попытался извлечь квалификатор из фиктивной зависимости, но он пуст.

Будет полезно узнать, как я могу правильно заменить зависимость на @Qualifier, чтобы имитировать объект.


  • добавление «@Autowired» вместе с «@Qualifier» в ваш класс контроллера может помочь вам 25.09.2014

Ответы:


1

Изменить: добавлена ​​ссылка на альтернативы вайтбоксу, она исчезает в более поздних версиях Mockito.

Можно использовать mockitos @Mock и @InjectMocks для внедрения в класс вещей, которые вы хотите протестировать, как это предлагается в другом посте. Раньше я думал, что это отличный способ протестировать bean-компоненты, управляемые Spring, но теперь я думаю, что это проблематично; если инъекция, сделанная @InjectMocks, не удалась, она делает это молча, и вы не знаете, почему. При создании теста им можно управлять, но когда у вас есть такие тесты, и несколько тестов начинают давать сбой с нулевыми указателями из-за небольшого непреднамеренного изменения контекста приложения, которое кто-то сделал, или после слияния, которое внесло незначительную аномалию, или подобное, это становится более запутанным, чем должно быть.

Вместо этого я советую вам использовать mockitos Whitebox, см. мой пример ниже. С его помощью вы можете явно указать, какое поле вы хотите «внедрить» с каким объектом, а в сложных ситуациях вы можете ввести более одного объекта. Mockito использует Whitebox при внедрении (но проглатывает все исключения).

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration( /*something that fits your setup*/ )
public class ControllerTest {
    @Autowired
    private PasswordService passwordService ;
    @Autowired
    private Validator validator;
    @Autowired
    private ReportService reportService;



    @Autowired
    private Controller testObject;

    @Before
    public void setupBefore() {

        //Since this "injection" is done manually the qualifiers does not matter
        Whitebox.setInternalState(testObject, "passwordService", passwordService);
        Whitebox.setInternalState(testObject, "validator", validator);
        Whitebox.setInternalState(testObject, "reportService", reportService);
    }

    @Test
    public void testSomething() {
    }
}

Если вы проводите регулярное модульное тестирование, Whitebox может помочь в тестировании без контекста Spring. Я очень рекомендую этот подход (но это немного не по теме, и я не буду публиковать пример, который я написал до того, как заметил, что вы делаете интеграционные тесты;)).


Редактировать: если вы используете более поздние версии Mockito, вы заметите, что Whitebox исчез, так что же делать вместо этого? Я столкнулся с этой ситуацией и попросил совета: Что мне использовать вместо Whitebox в Mockito 2.2 для установки полей?

30.11.2014
  • Какая невероятно мощная техника. Будьте здоровы. 09.03.2015
  • Большое спасибо. Этот ответ помог. 27.03.2019
  • @Sam - Если вы хотите перейти на более новые версии Mockito, см. ссылку, которую я добавил в конце моего ответа. 27.03.2019

  • 2

    Вам больше не нужно этого делать. Сам Mockito, начиная с версии 1.8.3, теперь поддерживает аннотированные моки и фиктивные инъекции, как описано здесь: http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Mockito.html#21

    Теперь мы делаем следующее для наших модульных тестов:

    // No annotation required
    public class SomeTest {
    
      @Mock
      private SomeDependency someDependency;
      @Mock
      private SomeDependency2 someDependency2;
      @InjectMocks
      private ClassUnderTest classUnderTest;
    
      @BeforeMethod(alwaysRun = true)
      public void setUp() {
        MockitoAnnotations.initMocks(this);
      }
    
      public void testSomething() {
        // Do your Mockito test here.
      }
    }
    
    16.11.2014
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..