【问题标题】:Cannot inject @Service in Unit Test in SpringBoot project无法在 SpringBoot 项目的单元测试中注入 @Service
【发布时间】:2018-03-26 16:22:04
【问题描述】:

我有一个@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);
}

【问题讨论】:

    标签: spring-boot spring-boot-test


    【解决方案1】:

    你应该使用 spring boot runner 来运行你的测试

    【讨论】:

      【解决方案2】:

      如果您想在测试执行期间加载和使用 Spring 上下文,则必须使用 Spring 测试运行器。
      您没有指定任何运行程序,因此默认情况下它使用您的测试 API 的运行程序。这里可能是 JUnit 或 TestNG(使用的跑步者取决于指定的 @Test 注释)。
      此外,根据您的测试逻辑,您想调用“真实” REST 服务:

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

      要实现它,您应该加载 Spring 上下文并通过使用 @SpringBootTest 注释测试来加载 Spring Boot 容器。

      如果使用 Spring Boot 上下文,要在 Spring 上下文中模拟依赖项,则不能使用 Mockito 中的 @Mock,而是 Spring Boot 中的 @MockBean
      要了解两者的区别,可以参考这个question

      请注意,如果您使用@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,而是使用泛型类型。

      【讨论】:

      • 我没有修改这部分。我专注于注射问题。但你可能是对的。我还注意到,OP 没有对检索到的 List 做出任何断言。
      • 我已经添加了 SpringBootTest 和 MockBean 注释,但现在我得到一个空上下文:“原因:java.lang.IllegalArgumentException:无法使用 NULL 'contextLoader' 加载 ApplicationContext。考虑注释你的测试带有@ContextConfiguration 或@ContextHierarchy 的类。"
      【解决方案3】:

      我想通了,我正在使用 Mockito 并用它来注释我的测试类。这让我可以模拟我正在尝试使用的服务类。

      @RunWith(MockitoJUnitRunner.class)
       public class SmartHomeControllerTest {..
           @Mock
           private DeviceService deviceService;
        }
      

      【讨论】:

        【解决方案4】:

        尝试使用@InjectMock 而不是@Mock

        【讨论】:

          【解决方案5】:
          @RunWith(SpringJUnit4ClassRunner.class)  
          @SpringBootTest(classes = NotificationApplication.class)  
          public class EmailClientImplTest {  
          ...  
          }  
          

          并在
          中添加所需的属性/配置 /src/测试/resources/application.yml

          祝你好运!

          【讨论】:

            猜你喜欢
            • 2019-06-01
            • 2021-05-17
            • 2016-02-16
            • 1970-01-01
            • 2018-08-09
            • 2013-07-08
            • 1970-01-01
            • 1970-01-01
            • 2017-02-05
            相关资源
            最近更新 更多