使用 Geb 进行 Spring MVC 测试

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

在我的第三篇文章中,我讨论了如何使用WebDriver通过页面对象模式来简化测试设计。在这篇文章中,我将讨论如何使用Geb使我们使用MockMvc进行测试更加 Groovy。

为什么选择 Geb 和 MockMvc

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


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


更新依赖项

在使用项目之前,您必须确保更新您的依赖项。站点文档中提供了有关MavenGradle的说明。

使用 Geb

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

创建 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 依赖项,如更新依赖项部分所示。这就是为什么@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 测试设计。最明显的变化是我们现在正在使用页面对象模式。正如我们在为什么选择 WebDriver?中提到的,我们可以在 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 式导航器 API来选择我们感兴趣的内容。

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

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

请提供反馈!

如果您对本博客系列或 Spring Test MVC HtmlUnit 有任何反馈,我鼓励您通过以下评论、github 问题或在 Twitter 上向我发送消息@rob_winch来联系我们。当然,最好的反馈是以贡献的形式出现。

获取 Spring 时事通讯

与 Spring 时事通讯保持联系

订阅

领先一步

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

了解更多

获取支持

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

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部