Как я могу имитировать некоторые вызовы методов bean-компонента, но использовать определенный bean-компонент в вызовах других методов в том же тестовом классе?

Я пытаюсь протестировать интерфейс службы, который имеет указанную реализацию в TestConfiguration. В интерфейс службы внедряется интерфейс DAO, который также имеет указанную реализацию в TestConfiguration. Реализация службы определяется как реальная служба, которая будет запущена в производство, а тестовый DAO — это новая пользовательская реализация интерфейса.

В 95% случаев я хочу использовать тестовую реализацию DAO. Однако в некоторых тестах я хочу переопределить функциональность DAO. Поскольку существует так мало случаев, когда я хочу переопределить DAO, я хочу просто издеваться над использованием Mockito на условной основе, не создавая другую реализацию интерфейса DAO (для крайних случаев, таких как возврат пустого списка из DAO). В идеале они должны относиться к тому же классу, который посвящен тестированию службы.

Я попытался использовать аннотацию @Spy для DAO Bean в тестовом классе. Я попытался использовать @MockBean в компоненте DAO. Я пытался использовать doReturn Mockito, и когда функция перезаписывает реализацию DAO по умолчанию, я всегда возвращаю результат из реализации Test DAO, определенной в TestConfiguration.

Я изменил текст того, что я делаю, поскольку это код компании, но это именно то, что я пытаюсь сделать иначе.

Моя TestConfiguration определена так

@TestConfiguration
public class TestAppConfiguration {

    @Bean
    public PersonService personService() {
        return new PersonServiceImpl(personDao());
    }  

    @Bean
    public PersonDao personDao() {
        return new TestPersonDaoImpl();
    }
}

Моя реализация службы выглядит следующим образом

public class PersonServiceImpl implements PersonService {
    private Logger logger = LoggerFactory.getLogger(PersonServiceImpl.class);

    private PersonDao personDao;

    public PersonServiceImpl(PersonDao personDao){
        this.personDao = personDao;
    }

    @Override
    public List<PersonDto> getAllPersons() {
        return personDao.findAll().stream()
                .map(person -> PersonDtoFactory.getPersonDto(person))
                .collect(Collectors.toList());
    }

    @Override
    public PersonDto getPersonById(Long id) {
       return PersonDtoFactory.getPersonDto(personDao.findById(id));

    }
}

Моя тестовая реализация DAO выглядит следующим образом

public class TestPersonDaoImpl implements PersonDao {

    @Override
    public List<PersonModel> findAll() {
        return getPersons();
    }

    @Override
    public List<PersonModel> findById(id) {
        return getPersons().stream()
                       .filter(person -> person.getId() == id)
                                   .collect(Collectors.toList());
    }

    private List<PersonModel> getPersons() {
        List<PersonModel> personList = new ArrayList<>();
        personList.add(new PersonModel(1L, "Susan");
        personList.add(new PersonModel(2L, "Jerry");
        personList.add(new PersonModel(3L, "Tom");
        return personList;
    }
}

И, наконец, мой тестовый класс обслуживания

@RunWith(SpringRunner.class)
@Import(TestAppConfiguration.class)
public class PersonServiceTests {
    //We won't test web socket functionality in this test class.
    @Autowired
    private PersonService personService;

    @MockBean //want to overwrite in the test only when specified in the test, otherwise, use default TestPersonDaoImpl bean.
    private PersonDao personDao;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void getAllPersons() {
        assert(personService.getAllTests().size() > 0);
    }

    @Test
    public void getPersonById() {
        assert(personService.getPersonById(1L).getName().equals("Susan"));
    }

    @Test
    public void getAllPersons_NoPersons(){
        //Mock the DAO call since it will have all of the test data by default
        doReturn(new ArrayList<Person>()).when(personDao).findAll();
        //when(personDao.findAll()).thenReturn(new ArrayList<>());  <-- this also doesn't work
        assert(personService.getAllPersons().size() == 0);
}

Ожидается, что все тесты будут пройдены, а вызов DAO будет перезаписан при вызове в реализации службы. Фактический результат состоит в том, что первые два теста проходят успешно, а третий тест завершается неудачно, потому что он не перезаписывает вызов dao.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
306
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С @MockBean вы получите внедренный фиктивный экземпляр.

С @Spy ваш дао не будет внедрен в сервис

Вам нужно @SpyBean .. вы получите инъекцию и вызов всех методов, поскольку они реализованы по умолчанию.

Другие вопросы по теме