Java / Spring: initMocks класс, который получил @Value из файла yml - PullRequest
1 голос
/ 17 февраля 2020

Я пишу модульные тесты для класса обслуживания, как показано ниже:

@Component
@Profile({"default", "dev"})
public class MyService {
    @Value("${my.property}")
    private String property;

    private OtherService otherService;

    public void MyMethod() {
        String myVar = otherService.method();

        return String.format("MyVar %s & MyProperty %s", myVar, property);
    }
}

Мой текущий класс теста для этого теста выглядит следующим образом:

@ActiveProfiles("dev")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MyApplication.class)
public class MyServiceTest {
    @Mock
    private OtherService otherService;

    @InjectMocks
    private MyService myService;

    @BeforeEach() 
    public void init() {
        MockitoAnnotations.initMocks(this);

        when(otherService.method()).thenReturn("a string");
    }

    @Test
    public void shouldReturnException() {
        final Exception exception = assertThrows(ApiErrorException.class,
        () -> myService.myMethod(var));

    assertThat(exception).hasMessage("here the message");

    verify(otherService, never()).method();
    }
}

С этими двумя классами я иметь application.yml & application-dev.yml для установки my.property. Я хочу получить свойство из файла application-dev во время выполнения моих тестов. Но с @InjectMocks свойство равно нулю. Принимая во внимание, что, используя @Autowired вместо / с @InjectMocks, переменная свойства устанавливается со значением, присутствующим в файле.

Проблема, при использовании Autowired с / вместо InjectMock приводит к переменной otherService будучи инициализированным, поэтому макет не создается.

Как я могу по-прежнему использовать Mockito, имея переменную свойства, установленную со значением в файле? Я видел около ReflectionTestUtils.setField, но использование его означает отсутствие использования файла yml (который я не фанат).

Хорошего дня


С помощью @ Deadpool, тесты могут использовать значения, записанные в файле application.yml. Но, используя @MockBean и @Autowired, тесты получают поведение, которое я не понимаю.

Пример: я проверяю, что метод возвращает исключение, и проверяю, что другие методы не вызываются после того, как исключение было перехвачено: verify(otherService, never()).otherMethod(); Запись этой строки возвращает следующую ошибку org.mockito.exceptions.verification.NeverWantedButInvoked.

Исходное исключение правильно перехвачено, но тест, похоже, не подтверждает, что никакие другие службы не должны вызываться.

Ответы [ 2 ]

1 голос
/ 17 февраля 2020

@ SpringBootTest используется для интеграционного тестирования, которое загружает ApplicationContext, который будет использоваться для тестовой среды

Аннотация @SpringBootTest может использоваться, когда нам нужно bootstrap весь контейнер. Аннотация работает с созданием ApplicationContext, который будет использоваться в наших тестах.

Поскольку вы генерируете среду интеграции с использованием @SpringBootTest, вам необходимо смоделировать bean-компонент с помощью @ MockBea n аннотация

@ActiveProfiles("dev")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MyApplication.class)
public class MyServiceTest {

   @MockBean
   private OtherService otherService;

   @Autowire
   private MyService myService;

   @BeforeEach
   public void init() {

    when(otherService.method()).thenReturn("a string");
   }
}
0 голосов
/ 17 февраля 2020

Я предлагаю вам изменить класс MyService, чтобы он принимал OtherService либо через конструктор, либо через сеттер. Примерно так:

@Component
@Profile({"default", "dev"})
public class MyService {
    @Value("${my.property}")
    private String property;

    private OtherService otherService;

    public MyService(OtherService otherService) {
        this.otherService = otherService
    }

    public void MyMethod() {
        String myVar = otherService.method();

        return String.format("MyVar %s & MyProperty %s", myVar, property);
    }
}

А потом вы проводите свой тест так:

@ActiveProfiles("dev")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MyApplication.class)
public class MyServiceTest {
    @Mock
    private OtherService otherService;

    @InjectMocks
    @Autowired
    private MyService myService;

    @BeforeEach() 
    public void init() {
        MockitoAnnotations.initMocks(this);

        when(otherService.method()).thenReturn("a string");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...