【问题标题】:Spring boot rest api mockito + mockmvc persistencespring boot rest api mockito + mockmvc 持久化
【发布时间】:2019-10-29 09:34:13
【问题描述】:

我想为我的休息控制器创建Test

@Controller
@RequestMapping("/v2/api/show/project")
public class ApiAccessController {
    private final ApiAccessService apiAccessService;

    @Autowired
    ApiAccessController(ApiAccessService apiAccessService){
        this.apiAccessService = apiAccessService;
    }
    @PutMapping(value = "/{id}/apikey")
    public ResponseEntity<ApiKeyResponse> generateApiKey(@PathVariable("id")Long id, Principal principal) {
        return apiAccessService.generateApiKey(id, principal.getName());
    }
}

我的测试如下:

@RunWith(SpringJUnit4ClassRunner.class)
public class ApiAccessControllerTest {
    private MockMvc mockMvc;
    Principal principal = new Principal() {
        @Override
        public String getName() {
            return "TEST_PRINCIPAL";
        }
    };

    @InjectMocks
    ApiAccessController apiAccessController;
    @Mock
    ProjectRepository projectRepository;

    @Before
    public void setUp(){
        mockMvc = MockMvcBuilders.standaloneSetup(apiAccessController).build();
    }
    @Test
    public void testGenerateApiKey() throws Exception {
        Project project = new Project();
        project.setId((long) 1);
        project.setName("test");
        project.setDescription("testdesc");
        project.setCiid("ciid");
        when(projectRepository.save(any(Project.class))).thenReturn(project);
        mockMvc.perform(MockMvcRequestBuilders.put("/v2/api/show/project/" + project.getId() +"/apikey").principal(principal))
                .andExpect(MockMvcResultMatchers.status().isOk());
    }
}

创建项目然后在这个项目上运行 generateApiKey,但是我得到 NullpointerException 看起来像模拟控制器找不到创建的实体

在我刚开始测试时,谁能指出我正确的方向?

【问题讨论】:

    标签: spring-boot junit mockito


    【解决方案1】:

    您应该模拟 ApiAccessService 而不是 ProjectRepository。 看看代码:

    @RunWith(SpringJUnit4ClassRunner.class)
    public class ApiAccessControllerTest {
        private MockMvc mockMvc;
        private Principal principal = () -> "TEST_PRINCIPAL";
    
        @InjectMocks
        private ApiAccessController apiAccessController;
    
        @Mock
        private ApiAccessService apiAccessService;
    
        @Before
        public void setUp() {
            mockMvc = MockMvcBuilders.standaloneSetup(apiAccessController).build();
        }
    
        @Test
        public void testGenerateApiKey() throws Exception {
            long id = 1L;
            when(apiAccessService.generateApiKey(id, principal.getName())).thenReturn(new ApiKeyResponse(111L));
    
            mockMvc.perform(MockMvcRequestBuilders.put("/v2/api/show/project/{id}/apikey", id).principal(principal))
                    .andExpect(MockMvcResultMatchers.status().isOk());
        }
    }
    

    如果您想创建集成测试,即测试 ApiAccessController -> ApiAccessService -> ProjectRepository 集成,您需要加载上下文(例如使用 @SpringBootTest)。

    另外你需要修复控制器,使用ResponseEntity.ok(...)

    @PutMapping(value = "/{id}/apikey")
    public ResponseEntity<ApiKeyResponse> generateApiKey(@PathVariable("id") Long id, Principal principal) {
        return ResponseEntity.ok(apiAccessService.generateApiKey(id, principal.getName()));
    }
    

    您可以在此存储库 MVC tests examples 中找到所有测试类型的非常好的示例

    【讨论】:

    • 它有效,但有两个问题,为什么这个{}} 有效而{} 无效?老实说,这种测试有什么意义?在测试中创建了 ApiKeyResponse 并检查是否设置了对象。我想测试 apiAccessService.generateApiKey 逻辑,最后验证生成的 apikey 格式是否正确(尚未完成,因为我无法创建基本测试)
    • 对不起,我的错字,应该是"/v2/api/show/project/{id}/apikey"。它是控制器的单元测试。它速度很快,可以立即对您的更改做出响应。您想要的是集成或系统测试,它需要上下文和环境加载。它们很慢,通常用作提交前的最后检查。您可以从 Martin Fowler 的文章 martinfowler.com/articles/practical-test-pyramid.html 中获得有关测试类型和“测试金字塔”的更多信息
    【解决方案2】:

    您正在创建的 Mock 未在 Controller 中引用。您在 Controller 中引用的 Service 不是您的测试设置的一部分。因此,对 Service 的任何访问都将导致 NullPointerException,因为未设置 Service

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-27
      • 1970-01-01
      • 2017-06-11
      • 2016-02-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2020-07-09
      相关资源
      最近更新 更多