Невозможно внедрить @Service в модульный тест в проекте SpringBoot

у меня есть @Service, который я пытаюсь смоделировать в модульном тесте, но пока получаю нулевое значение. В классе приложения я указываю, что такое scanBasePackages. Должен ли я сделать это по-другому? Спасибо.

Это мой класс обслуживания, который реализует интерфейс:

@Service
public class DeviceService implements DeviceServiceDao {

private List<Device> devices;

@Override
public List<Device> getDevices(long homeId) {
    return devices;
}

}

Это мой модульный тест.

public class SmartHomeControllerTest {

    private RestTemplate restTemplate = new RestTemplate();
    private static final String BASE_URL = “..”;

    @Mock
    private DeviceService deviceService;

@Test
public void getHomeRegisteredDevices() throws Exception {

    Device activeDevice = new DeviceBuilder()
            .getActiveDevice(true)
            .getName("Alexa")
            .getDeviceId(1)
            .getHomeId(1)
            .build();
    Device inativeDevice = new DeviceBuilder()
            .getInactiveDevice(false)
            .getName("Heater")
            .getDeviceId(2)
            .getHomeId(1)
            .build();

    UriComponentsBuilder builder = UriComponentsBuilder
            .fromUriString(BASE_URL + "/1/devices");

    List response = restTemplate.getForObject(builder.toUriString(), List.class);

    verify(deviceService, times(1)).getDevices(1);
    verifyNoMoreInteractions(deviceService);
}

person Gabi Radu    schedule 14.10.2017    source источник


Ответы (5)


Вы должны использовать средство запуска тестов Spring, если хотите загружать и использовать контекст Spring во время выполнения тестов.
Вы не указываете какое-либо средство выполнения, поэтому по умолчанию используется средство выполнения вашего тестового API. Здесь, вероятно, JUnit или TestNG (используемый раннер зависит от указанной аннотации @Test).
Кроме того, согласно логике вашего теста, вы хотите вызвать «настоящую» службу REST:

List response = restTemplate.getForObject(builder.toUriString(), 
List.class);

Для этого вы должны загрузить контекст Spring и загрузить контейнер Spring Boot, аннотировав тест с помощью @SpringBootTest.

Если вы используете контекст Spring Boot, чтобы имитировать зависимость в контексте Spring, вы не должны использовать @Mock из Mockito, а @MockBean из Spring Boot.
Чтобы понять разницу между ними, вы можете обратиться к этому вопрос.

Обратите внимание, что если вы используете аннотацию @SpringBootTest, TestRestTemplate будет автоматически доступна и может быть автоматически подключена к вашему тесту.
Но будьте осторожны, это отказоустойчиво. Это может быть подходящим или нет в соответствии с вашими тестами.

Таким образом, ваш код может выглядеть так:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SmartHomeControllerTest {

    private static final String BASE_URL = “..”;

    @Autowired
    private TestRestTemplate restTemplate;

    @MockBean
    private DeviceService deviceService;

    @Test
    public void getHomeRegisteredDevices() throws Exception {        
       ...
    }

В качестве примечания: избегайте использования необработанного типа в качестве List, но отдавайте предпочтение общему типу.

person davidxxx    schedule 14.10.2017
comment
Я не модифицировал эту часть. Я сосредоточился на проблеме инъекций. Но вы, наверное, правы. Я также отмечаю, что ОП не делает никаких утверждений о полученном List. - person davidxxx; 14.10.2017
comment
Я добавил аннотацию SpringBootTest и MockBean, но теперь я получаю нулевой контекст: Вызвано: java.lang.IllegalArgumentException: невозможно загрузить ApplicationContext с NULL 'contextLoader'. Попробуйте аннотировать свой тестовый класс с помощью @ContextConfiguration или @ContextHierarchy. - person Gabi Radu; 15.10.2017

@RunWith(SpringJUnit4ClassRunner.class)  
@SpringBootTest(classes = NotificationApplication.class)  
public class EmailClientImplTest {  
...  
}  

А также добавьте необходимые свойства/конфигурации в
/src/test/resources/application.yml

Удачи!

person panayot_kulchev_bg    schedule 31.01.2019

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

@RunWith(MockitoJUnitRunner.class)
 public class SmartHomeControllerTest {..
     @Mock
     private DeviceService deviceService;
  }
person Gabi Radu    schedule 15.10.2017

Попробуйте использовать @InjectMock вместо @Mock

person MGPJ    schedule 15.10.2017

Вы должны запустить свой тест с весенним загрузчиком

person Alexander.Furer    schedule 14.10.2017