我正在为我的控制器类编写测试用例,这是一个Spring Boot应用程序,我想只为控制器类编写测试用例,它调用服务和服务到存储库。我正在使用SpringBootTest,它用于为我的所有bean创建实例。我想只模拟数据库调用和外部api调用。
MyController {
@Autowired
MyService service;
//Api call for getDetails
service.getDetails();
}
MyService {
@Autowired
MyRepository repo;
}
MyControllertest {
@Autowired
MyController controller;
@Mock
MyRepository repoMock;
@Before
public void setup(){
// intit mocks
}
@Test
public void myTest(){
when(repoMock.getDetails()).thenReturn(null);
controller.getdetails();
}
}
当我运行测试用例时,它不使用模拟存储库,而是使用Service类中提到的@Autowired
存储库。
任何人都可以解释我如何从控制器类模拟存储库。
在这个博客中发布了这么多问题,但没有得到任何回复。
它没有使用你的Mocks,因为你没有将这些模拟注入你的控制器/服务类。相反,你是自动装配它。 正确的做法是
@RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
@InjectMocks
MyController controller;
.....
}
更好的解决方案是摆脱Field Injection并使用Constructor Injection
例如,在Controller和Service类中。您可以在Contructor上执行此操作,而不是在Fields上使用@Autowired。例如
class MyService {
private final MyRepository repo;
@Autowired
public MyService(final MyRepository repo) {
this.repo = repo;
}
}
同样在Controller类中
class MyController {
@Autowired
private final MyService service;
public MyController(final MyService service) {
this.service = service
}
}
这样做可以帮助您在运行时轻松设置模拟。例如,在您的测试类中,您可以这样做
@RunWith(MockitoJUnitRunner.class)
public class MyControllertest {
MyController controller;
MyService service;
@Mock
MyRepository repoMock;
@Before
public void setup(){
// init mocks
service = new MyService(repoMock);
controller = new MyController(service);
}
..............
}
Here是关于Field注入的好文章
你不能打电话
MockitoAnnotations.initMocks(this);
在setUp
方法,因为SpringRunner
已经初始化了嘲笑。通过调用initMocks
,您可以为repoMock
分配一个新对象。像when
这样的所有Mockito动作都是在新对象上执行的,但是Spring仍然使用由MyRepository
创建的“旧”SpringRunner
。
解决这个问题的3种方法:
1.与Mockito一起。
@Mock
MyRepository repoMock;
@InjectMocks
MyService service;
这样做的是它按类类型匹配MyService类字段,并将Mocked变量分配给这些字段。所以它会为你的服务注入嘲笑。这与Spring无关。
2.重构MyService构造函数,因此依赖项可以通过构造函数注入。 @Autowired也与构造函数一起工作,因此它是首选方式。
@Autowired
public MyService(MyRespoitory repository){
this.repository = repository;
}
3.使用Springs测试环境:
https://docs.spring.io/spring-security/site/docs/current/reference/html/test-mockmvc.html
并定义一个bean,它是存储库的模拟版本
@Bean
public MyRepository mockMyRepository(){
return mock(MyRespository.class);
}
这对于服务测试来说可能是缓慢且令人厌烦的。
第二个是最优选和最简单的方法。
这对我有用:
@MockBean
private OrderRepository orderRepository;
@SpyBean
private OrderService orderService;
@InjectMocks
private OrderController orderController;