SpringBoot中普通类无法注入service的解决方案
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot中普通类无法注入service的解决方案相关的知识,希望对你有一定的参考价值。
参考技术A 先摆出实际问题:本人在项目中写了钩子方法,在service方法中,通过父类方法,调用子类的实现,结果出现,service无法注入问题?解决方案:既然spring无法完成普通类的依赖注入,那么我们就手动getBean(思路就是手动调用ApplicationContext.getBean() )。
无法在 SpringBoot 项目的单元测试中注入 @Service
【中文标题】无法在 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的解决方案的主要内容,如果未能解决你的问题,请参考以下文章
Springboot 定时任务,service层无法注入问题详细解决
springboot中如何注入一个多个实现类service接口
SpringBoot 拦截器中无法使用 @Autowired 注入 Service