无法在 SpringBoot 项目的单元测试中注入 @Service
Posted
技术标签:
【中文标题】无法在 SpringBoot 项目的单元测试中注入 @Service【英文标题】:Cannot inject @Service in Unit Test in SpringBoot project 【发布时间】: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);
【问题讨论】:
【参考方案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
祝你好运!
【讨论】:
以上是关于无法在 SpringBoot 项目的单元测试中注入 @Service的主要内容,如果未能解决你的问题,请参考以下文章
Java教程:Springboot项目如何使用Test单元测试
Springboot单元测试调用Service或Dao方法出现空指针异常
Springboot单元测试调用Service或Dao方法出现空指针异常
记录Spring Boot大坑一个,在bean中如果有@Test单元测试,不会注入成功