使用 Geb 进行 Spring MVC 测试

工程 | Rob Winch | 2014 年 4 月 15 日 | ...

在我的第三篇文章中,我讨论了如何使用WebDriver 并结合 Page Object 模式来简化测试设计。在这篇文章中,我将讨论如何使用Geb 来使我们使用 MockMvc 进行测试更加 Groovy 化。

为何选择 Geb 和 MockMvc

Geb 以 WebDriver 为基础,因此它提供了与 WebDriver 相同的许多优点。然而,Geb 通过为我们处理一些样板代码,使事情变得更加简单。当然,我们希望使用 MockMvc,这样我们就无需将代码部署到服务器。理解使用 Geb 的好处的最简单方法是进入一个示例。


注意:Geb 的另一个很棒的特性是其出色的文档


更新依赖项

在使用该项目之前,您必须确保更新您的依赖项。MavenGradle 的说明都可以在站点文档中找到。

使用 Geb

现在我们已经拥有正确的依赖项,可以在单元测试中使用 Geb。使用 Geb 和 Spring MVC Test 的完整代码示例可以在 GebCreateMessagesSpec 中找到。

创建 MockMvc 实例

为了使用 HtmlUnit 和 Spring MVC Test,我们必须首先创建一个 MockMvc 实例。关于如何创建 MockMvc 实例有很多文档,但本节我们将快速回顾如何创建一个 MockMvc 实例。

第一步是创建一个新的 GebReportingSpec 类,并按如下所示进行注解

@ContextConfiguration(classes=[WebMvcConfig,MockDataConfig])
@WebAppConfiguration
class GebCreateMessagesSpec extends GebReportingSpec {
  @Autowired
  WebApplicationContext context;

  WebDriver driver;

  ...
}
  • 为此,请确保添加 spock-spring 依赖项,如updating-dependencies 部分所示。这就是 @Autowired 注解会被遵守的原因。
  • @ContextConfiguration 告诉 Spring 要加载哪些配置。您会注意到,我们正在加载数据层的模拟实例,以提高测试性能。如果需要,我们可以选择针对真实数据库运行测试。但是,这会带来我们之前提到的缺点。
  • @WebAppConfiguration 表示应创建一个 WebApplicationContext,而不是 ApplicationContext

接下来,我们需要从 context 创建我们的 MockMvc 实例。下面提供了一个如何执行此操作的示例

def setup() {
  MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build()
  ...
}

当然,这只是创建 MockMvc 实例的一种方法。我们可以决定添加一个 Servlet 过滤器,使用独立设置等。重要的是我们需要一个 MockMvc 实例。有关创建 MockMvc 实例的更多信息,请参阅 Spring MVC Test 文档

初始化 WebDriver

现在我们已经创建了 MockMvc 实例,我们需要创建一个 MockMvcHtmlUnitDriver,以确保我们使用在上一步中创建的 MockMvc 实例。然后,我们使用 Geb 的显式生命周期并在 Geb 的Browser 实例上设置驱动程序。

WebDriver driver;

def setup() {
  MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build()
  driver = new MockMvcHtmlUnitDriver(mockMvc, true)
  browser.driver = driver
}

def destroy() {
  if(driver != null) {
    driver.close();
  }
}

使用 Geb

现在我们可以像通常一样使用 Geb,而无需部署我们的应用程序。例如,我们可以使用以下方式请求视图来创建消息

to CreateMessagePage

然后我们可以填写表单并提交以创建消息。

form.summary = expectedSummary
form.text = expectedMessage
submit.click(ViewMessagePage)

任何未识别的方法调用或未找到的属性访问/引用都将被转发到当前页面对象。这消除了我们直接使用 WebDriver 时所需的许多样板代码。

此外,这也改进了我们的 HtmlUnit 测试的设计。最明显的变化是现在我们使用了 Page Object 模式。正如我们在为何选择 WebDriver?中所述,我们可以将 Page Object 模式与 HtmlUnit 一起使用,但现在容易得多。

我们来看看我们的 CreateMessagePage

class CreateMessagePage extends Page {
  static url = 'messages/form'
  static at = { assert title == 'Messages : Create'; true }
  static content =  {
    submit { $('input[type=submit]') }
    form { $('form') }
    errors(required:false) { $('label.error, .alert-error')?.text() }
  }
}

您会注意到的第一件事是我们的 CreateMessagePage 扩展了 Page。我们不会详细介绍 Page,但总而言之,它包含了我们所有页面的基本功能。

您会注意到的下一件事是我们定义了一个可以找到此页面的 URL。这允许我们通过以下方式导航到该页面

to CreateMessagePage

我们还有一个闭包,用于判断我们是否位于指定的页面。如果我们在正确的页面上,它应该返回 true。这就是为什么我们可以断言我们在正确的页面上,如下所示


注意:我们在闭包中使用了断言,这样如果我们在错误的页面上,就可以确定问题出在哪里。


at CreateMessagePage

最后,我们创建一个内容闭包,用于指定页面中所有感兴趣的区域。我们可以使用 类似 jQuery 的 Navigator API 来选择我们感兴趣的内容。

最后,我们可以验证新消息是否成功创建

at ViewMessagePage
success == 'Successfully created a new message'
id
date
summary == expectedSummary
message == expectedMessage

请提供反馈!

如果您对本博客系列或 Spring Test MVC HtmlUnit 有反馈,欢迎通过下方评论、github issues 或在 twitter 上联系我 @rob_winch。当然,最好的反馈是贡献

获取 Spring 新闻邮件

订阅 Spring 新闻邮件,保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅,提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部