使用Spock在控制器测试中的模拟弹簧服务



我正在寻找一种模拟控制器中使用的服务bean的方法,以便我只能使用MOCKMVC测试控制器。但是我找不到一种简单的方法来用Spock模拟替换真实的豆。一切都使用Spring-boot 1.3.2版本。以下更多详细信息:

我有一个以下控制器类

@RestController
@RequestMapping(path = "/issues")
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class NewsletterIssueController {
  private final GetLatestNewsletterIssueService latestNewsletterIssueService;
  @RequestMapping(
    method = RequestMethod.GET,
    path = "/latest"
  )
  public ResponseEntity getLatestIssue() {
    Optional<NewsletterIssueDto> latestIssue = latestNewsletterIssueService.getLatestIssue();
    if (latestIssue.isPresent()) {
        return ResponseEntity.ok(latestIssue.get());
    } else {
        return ResponseEntity.notFound().build();
    }
  }
}

和此类的集成Spock测试:

@ContextConfiguration(classes = [Application], loader = SpringApplicationContextLoader)
@WebAppConfiguration
@ActiveProfiles("test")
class NewsletterIssueControllerIntegrationSpec extends Specification {
  MockMvc mockMvc
  @Autowired
  GetLatestNewsletterIssueService getLatestNewsletterIssueService
  @Autowired
  WebApplicationContext webApplicationContext
  def setup() {
    ConfigurableMockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(webApplicationContext)
    mockMvc = mockMvcBuilder.build()
  }
  def "Should get 404 when latest issue does not exist"() {
    given:
        getLatestNewsletterIssueService.getLatestIssue() >> Optional.empty() // this won't work because it is real bean, not a Mock
    expect:
        mockMvc.perform(MockMvcRequestBuilders
                .get("/issues/latest")
                .contentType(JVM_BLOGGERS_V1)
                .accept(JVM_BLOGGERS_V1)
        ).andExpect(MockMvcResultMatchers.status().isNotFound())
  }
}

我需要一种用模拟/存根替换此自动豆的方法

我将在测试中创建一个本地配置,并覆盖那里的bean。

我不知道Groovy,但它会在Java中使用:

@ContextConfiguration(classes = NewsletterIssueControllerIntegrationSpec.Conf.class, loader = SpringApplicationContextLoader.class)
@WebAppConfiguration
@ActiveProfiles("test")
class NewsletterIssueControllerIntegrationSpec extends Specification {
  @Configuration
  @Import(Application.class)
  public static class Conf {
    @Bean
    public GetLatestNewsletterIssueService getLatestNewsletterIssueService() {
      return mock(GetLatestNewsletterIssueService.class);
    }
  }
  // […]
}

警告:此方法与Mockito效果很好,但是您可能需要一个预释放版本的Spock才能起作用,参考:https://github.com/spockframework/spockframework/spock/spock/pull/546

顺便说一句:Spring Boot 1.4将提供@MockBean的构造来简化这一点。

使用SPOCK 1.2您可以使用Springbean注释在弹簧上下文中注入模拟的服务春季整合测试/

因此,使用此新注释,您的测试将是:

@WebMvcTest(controllers = [NewsletterIssueController], secure = false)
@AutoConfigureMockMvc
@ActiveProfiles("test")
class NewsletterIssueControllerIntegrationSpec extends Specification {
  @Autowired
  MockMvc mockMvc
  @SpringBean
  GetLatestNewsletterIssueService getLatestNewsletterIssueService

  def setup() {
      // nothing to do as SpringBean and WebMvcTest do the job for you
  }
  def "Should get 404 when latest issue does not exist"() {
    given:
        getLatestNewsletterIssueService.getLatestIssue() >> Optional.empty() // this won't work because it is real bean, not a Mock
    expect:
        mockMvc.perform(MockMvcRequestBuilders
                .get("/issues/latest")
                .contentType(JVM_BLOGGERS_V1)
                .accept(JVM_BLOGGERS_V1)
        ).andExpect(MockMvcResultMatchers.status().isNotFound())
  }
}

最新更新