使用 Spring Boot 和 JUnit 从控制器类模拟存储库



我正在为我的控制器类编写测试用例,这是一个 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));
}

相关内容

  • 没有找到相关文章

最新更新