Используйте реальный компонент в сервисном тесте

Я тестирую службу с вспомогательным компонентом с автоматическим подключением. Этот компонент имеет репозиторий с автоматическим подключением.

В своем тесте я хочу использовать этот помощник компонента, а не макет. И я хочу издеваться над репо для этого.

Но я не могу заставить его работать.

Сервис, который я тестирую:

@Service
public class ServiceImpl{
    @Autowired
    private Helper helper;
}

Класс Helper с автоматически подключенным репозиторием

@Component
public class Helper {
    @Autowired
    private Repository repo;
}

Мой тест должен быть таким

@ExtendWith(MockitoExtension.class)
public class ServiceImplTest {

    ServiceImpl service;

    @Mock
    private Repository repoMock;

    @InjectMocks
    private Helper helper;

}

Я хотел бы лучше реорганизовать все это, но, к сожалению, это невозможно...

Приветствуется любая помощь.


person moguil    schedule 27.03.2019    source источник
comment
Является ли Repository классом или интерфейсом?   -  person Lorelorelore    schedule 27.03.2019
comment
Репозиторий — это интерфейс   -  person moguil    schedule 27.03.2019


Ответы (4)


Я бы предпочел инъекцию конструктора, а не инъекцию поля. (подробнее здесь)

В этом случае ваши классы будут выглядеть примерно так:

    @Component
    public class Helper {
        @Autowired
        public Helper(Repository repo) {
            this.repo = repo;
        }
    }

    @Service
    public class ServiceImpl{
        @Autowired
        public ServiceImpl(Helper helper) {
            this.helper = helper;
        }
    }

Таким образом, вы можете легко создать настоящий объект Helper с фиктивным объектом Repository:

    ServiceImpl service;

    private Helper helper;

    @Mock
    private Repository repoMock;

    @BeforeEach
    void init() {
        helper = new Helper(repoMock);
        service = new ServiceImpl(helper);
    }
person Rashin    schedule 27.03.2019
comment
Я бы тоже предпочел, но, к сожалению, я не могу изменить класс, который тестирую. - person moguil; 27.03.2019

Наконец-то я нашел решение, спасибо за помощь.

@ExtendWith(MockitoExtension.class)
public class ServiceImplTest {

    @InjectMocks
    ServiceImpl service

    @Spy
    @InjectMocks
    private Helper helper;

    @Mock
    private Repository repoMock;

    @InjectMocks
    private Helper helper;
}

Таким образом, фиктивный репозиторий внедряется в помощника-шпиона, а помощник может быть внедрен в службу. Объекты @Spy фактически создаются, поэтому, если вы не заглушите ни один из его методов, вы получите «настоящий» объект.

Здесь фиктивный репозиторий внедряется в помощник, а помощник внедряется в службу.

person moguil    schedule 28.03.2019

Если Repository - это интерфейс (а не конкретный класс), вы можете попробовать следующее:

@ExtendWith(MockitoExtension.class)
public class ServiceImplTest {

    @Spy
    @InjectMocks
    ServiceImpl service = new ServiceImpl();

    @Mock
    private Repository repoMock;

    @InjectMocks
    private Helper helper;
}
person Lorelorelore    schedule 27.03.2019
comment
Проблема остается той же. Помощник имеет значение null при использовании в службе, потому что он не введен должным образом (не макет) - person moguil; 27.03.2019
comment
на самом деле решение было близко к вашему, но это помощник, который должен быть аннотирован с помощью @Spy. - person moguil; 28.03.2019

Попробуйте загрузить конфигурацию для своих тестов, которая отдает приоритет фиктивному репозиторию Проверено:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SomeTest {

    @Configuration
    static class ContextConfiguration {     

        @Bean
        public Helper helper() {
            return new Helper();
        }
        @Bean
        @Primary
        public Repository repoMock() {
            Repo repo = Mockito.mock(Repository.class);
            Mockito.when(/* Mock your repo */);
            return repo;
        }
    }

    @Autowired
    private Helper helper;

    @Test
    public void testMethod() {
        // Your test goes here
    }
}

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

См. также:

person Xtreme Biker    schedule 27.03.2019