我正在为我的控制器类编写测试用例,这是一个 Spring 启动应用程序,我只想为调用服务和服务到存储库的控制器类编写测试用例。我正在使用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
存储库。
任何人都可以解释一下如何从控制器类模拟存储库。
在这个博客中发布了这么多问题,但我没有得到任何回应。
它没有使用您的模拟,因为您没有将这些模拟注入到您的控制器/服务类中。相反,您正在自动布线。
正确的方法是
@RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
@InjectMocks
MyController controller;
.....
}
更好的解决方案是摆脱场注入并使用构造函数注入
例如,在控制器和服务类中。无需在字段上使用@Autowired,您可以在构造器上执行此操作。例如
class MyService {
private final MyRepository repo;
@Autowired
public MyService(final MyRepository repo) {
this.repo = repo;
}
}
在控制器类中类似
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);
}
..............
}
这是一篇关于场注入的好文章
这对我有用:
@MockBean
private OrderRepository orderRepository;
@SpyBean
private OrderService orderService;
@InjectMocks
private OrderController orderController;
你一定不能打电话
MockitoAnnotations.initMocks(this);
在setUp
方法中,因为SpringRunner
已经初始化了模拟。通过调用initMocks
,可以将新对象分配给repoMock
。所有 Mockito 操作(如when
)都是在新对象上执行的,但 Spring 仍然使用SpringRunner
创建的"旧"MyRepository
。
3 种解决此问题的方法:
1.一个是与莫基托。
@Mock
MyRepository repoMock;
@InjectMocks
MyService service;
这样做的作用是按类类型匹配 MyService 类字段,并将模拟变量分配给这些字段。因此,它将模拟注入您的服务。这与春天无关。
2.重构 MyService 构造函数,以便可以通过构造函数注入依赖项。 @Autowired也适用于构造函数,因此它是首选方式。
@Autowired
public MyService(MyRespoitory repository){
this.repository = repository;
}
3.使用弹簧测试环境:
https://docs.spring.io/spring-security/site/docs/current/reference/html/test-mockmvc.html
并定义一个 bean,它是存储库的模拟版本
@Bean
public MyRepository mockMyRepository(){
return mock(MyRespository.class);
}
对于服务测试来说,这可能既缓慢又令人厌烦。
第二个是最优选和最简单的方法。
这工作正常:
@WebMvcTest(MyController.class)
public class WebMockTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MyRepository repository;
@SpyBean
private MyService service;
@InjectMocks
private MyController controller;
@Test
public void saveTest() throws Exception {
String content = "";
long id=Long.MAX_VALUE;
Entity entityToSend = new Entity(id, content);
Gson gson = new Gson();
when(repository.save(any(Entity.class)).thenReturn(Optional.of(entityToSend));
mockMvc.perform(MockMvcRequestBuilders
.post("/api/save")
.content(gson.toJson(entityToSend))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Long.MAX_VALUE))
.andExpect(MockMvcResultMatchers.jsonPath("$.content").value(content));
}