首页 > 解决方案 > 如何通过自动装配服务在 spring-boot 上测试控制器层?

问题描述

我正在尝试在我的 API 中测试我的控制器的功能。我已经实现了以下服务,称为ExpertsServiceImpl.java


@Service
@RequiredArgsConstructor
public class ExpertsServiceImpl implements ExpertsService{

    private final ExpertRepository repository;



    @Override
    public Experts createExpert(Experts expert) {
        return repository.save(expert);
    }
    @Override
    public void deleteExpert(ObjectId id) {
        Experts deleted = findExpertById(id);
        if(deleted == null) {
            throw new ExpertNotFoundException(id);
        }
        repository.delete(deleted);
    }
    public Experts findExpertById(ObjectId id) {
        Optional<Experts> searchedExpert = repository.findById(id);
        if(searchedExpert.get() == null) {
            throw new ExpertNotFoundException(id);
        }
        return searchedExpert.get();
    }

这是我的MongoDB存储库:

public interface ExpertRepository extends MongoRepository<Experts, ObjectId>{

}

这是我的控制器类:


@RestController
@Validated
class ExpertController {

    public final ExpertsService service;
    public ExpertController(ExpertsService service) {
        this.service = service;
    }


    @PostMapping(path = "/experts/",
              consumes = {MediaType.APPLICATION_JSON_VALUE},
              produces = {MediaType.APPLICATION_JSON_VALUE}
           )
    public Experts newExpert(@Valid @RequestBody Experts newExpert) {
        return service.createExpert(newExpert);


    }

    @DeleteMapping("/experts/{id}")
    public void deleteBook(@PathVariable  ObjectId id) throws Throwable {
        service.deleteExpert(id);
    }

我正在为我的控制器编写以下测试类:

@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ExpertController.class)
class ExpertControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ExpertsService expertsService;

    @MockBean
    private ExpertRepository repository;

    Experts demoExpert = new Experts(ObjectId.get(),"Steve Jobs", "Enterpreneur",
                                     Availability.BUSY, Language.CHINESE);

    @Before
    public void setUp() throws Exception{
        expertsService.deleteAll();
        expertsService.createExpert(demoExpert);

    }

    @After
    public void tearDown() throws Exception{
        expertsService.deleteAll();
    }


    @Test
    public void deleteExpert() throws Exception {
        String expertId = demoExpert.getId();
        this.mockMvc.perform(MockMvcRequestBuilders
                .delete("/experts/{id}", expertId)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk());
    }

引发此错误:


java.lang.IllegalStateException: Failed to load ApplicationContext

    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
    at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.postProcessFields(MockitoTestExecutionListener.java:95)
    at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.injectFields(MockitoTestExecutionListener.java:79)
    at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.prepareTestInstance(MockitoTestExecutionListener.java:54)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:337)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:342)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:337)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)

有谁知道我该如何解决这个问题?我想这与我正在自动装配服务和模拟存储库这一事实有关,但不知道如何解决这个问题。我想自动连接服务,因为它对我的测试没有多大意义。任何人都知道我该怎么做?我很感激任何帮助

标签: javaspringmongodbspring-bootcontroller

解决方案


如果您不想模拟该服务,您可以@Import(ExpertsServiceImpl.class)在您的测试类之上添加或@SpringBootTest如前所述使用(但在这种情况下,它将加载整个应用程序,这并不是很好,性能方面)


推荐阅读