[翻译]Play框架1.2.7版本教程(10) - 完成应用测试

完成应用测试

咱们已经完成了咱们想要建立的博客引擎。不过这个项目还没有彻底结束。为了保证代码的质量,咱们须要添加更多的测试。css

固然咱们已经完成了测试全部模型层的功能。因此博客引擎的核心功能已经被测试过了。可是一个Web应用并不仅有模型层。咱们须要确保Web交互界面是否无缺。这须要测试引擎的控制层。可是咱们甚至须要测试UI界面,好比咱们的Javascript代码。html

测试控制层

经过JUnit,你能够直接测试应用的控制层。咱们将这些测试称之为功能测试。由于咱们会测试应用完整的功能。java

一个功能测试会调用Play的ActionInvoker,模拟一个HTTP请求。咱们须要提供HTTP方法,一个URI和HTTP参数。Play会根据这个请求,找到路由,接着调用对应的action,最后返回一个响应。你能够分析它,看看响应是否在乎料之中。segmentfault

先写第一个功能测试。打开yabe/test/ApplicationTest.java浏览器

import org.junit.*;
import play.test.*;
import play.mvc.*;
import play.mvc.Http.*;
import models.*;

public class ApplicationTest extends FunctionalTest {

    @Test
    public void testThatIndexPageWorks() {
        Response response = GET("/");
        assertIsOk(response);
        assertContentType("text/html", response);
        assertCharset("utf-8", response);
    }

}

看上去像是通常的JUnit测试。注意咱们使用Play的Functionaltest父类来获取辅助函数。这个测试仅仅是用于检测主页是否正常(通常/URL会渲染一个HTML文件,并返回‘200 OK’状态码)。安全

如今咱们将检测管理面板的安全是否禁得住考验。给ApplicationTest.java添加新的测试:cookie

…
@Test
public void testAdminSecurity() {
    Response response = GET("/admin");
    assertStatus(302, response);
    assertHeaderEquals("Location", "/login", response);
}
…

使用play test命令运行你的yabe应用,打开http://localhost:9000/@tests,选择ApplicationTest.java用例,而后运行它。mvc

变绿了吗?app

green

如今,咱们能够对应用的所有功能进行一样的测试,但这并非测试一个基于HTML的Web应用的最佳方式,咱们的博客引擎须要在Web浏览器中执行,若是可以在真实的浏览器中进行测试,这就是Play的Selenium测试所作的事情。框架

一个Selenium测试套件通常是个HTML文件。Selenium所使用的HTML语法有点使人乏味(就像是一个HTML表格元素同样)。好消息是,Play可让你使用模板引擎以及一些支持简化的Selenium语法的标签来生成它。这也意味着,你能够利用Play模板的表达能力(条件语句,循环语句等等)来生成许多复杂的测试。

固然,若是须要的话,你也能够不用模板的生成功能,直接撰写Selenium页面。其实,使用Selenium专用工具,好比Selenium IDE,来生成Selenium测试页面也是不错的选择。

一个刚建立的Play应用已经自带了一个Selenium测试。打开yabe/test/Application.test.html

*{ You can use plain Selenium commands using the selenium tag }*

#{selenium}
    // Open the home page, and check that no error occurred
    open('/')
    waitForPageToLoad(1000)
    assertNotTitle('Application error')
#{/selenium}

在yabe上运行这个测试应该不会出现任何问题。它只是打开主页,而后检测页面中是否包括"Application error"文本。

不过,一如任何复杂的测试,在浏览应用并进行测试以前,你都须要设置一些初始数据。咱们将重用以前用过的Fixture和yabe/test/data,yml。要在测试开始以前引入数据,仅需使用#{fixture /}标签:

#{fixture delete:'all', load:'data.yml' /}

#{selenium}
    // Open the home page, and check that no error occurred
    open('/')
    waitForPageToLoad(1000)
    assertNotTitle('Application error')
#{/selenium}

还须要检查另外一个重要的事情,就是在每一个测试开始以前要有一个新的用户会话。这个会话将保持在浏览器的持久cookie中,若是不作清理,它会在两个连续的测试之间保持。

因此咱们的测试以前,先添加一个特殊的命令:

#{fixture delete:'all', load:'data.yml' /}

#{selenium}
    clearSession()

    // Open the home page, and check that no error occurred
    open('/')
    waitForPageToLoad(1000)
    assertNotTitle('Application error')
#{/selenium}

运行这个测试,确保一切安好。应该会是全绿的结果。

因此咱们能够开始写更复杂的测试了。打开主页面,检查是否展现了默认的文章。

#{fixture delete:'all', load:'data.yml' /}

#{selenium 'Check home page'}
    clearSession()

    // Open the home page
    open('/')

    // Check that the front post is present
    assertTextPresent('About the model layer')
    assertTextPresent('by Bob, 14 Jun 09')
    assertTextPresent('2 comments , latest by Guest')
    assertTextPresent('It is the domain-specific representation')

    // Check older posts
    assertTextPresent('The MVC application')
    assertTextPresent('Just a test of YABE')
#{/selenium}

咱们使用的是标准的Selenium语法,叫作Selenese

运行它。(经过在新的标签页打开连接,你能够在一个不一样的窗口中运行)。

run

如今咱们开始测试评论框。添加一个新的#{selenium /}标签到模板中:

#{selenium 'Test comments'}

    // Click on 'The MVC application post'
    clickAndWait('link=The MVC application')
    assertTextPresent('The MVC application')
    assertTextPresent('no comments')

    // Post a new comment
    type('content', 'Hello')
    clickAndWait('css=input[type=submit]')

    // Should get an error
    assertTextPresent('no comments')
    assertTextPresent('Author is required')
    type('author', 'Me')
    clickAndWait('css=input[type=submit]')

    // Check
    assertTextPresent('Thanks for posting Me')
    assertTextPresent('1 comment')
    assertTextPresent('Hello')
#{/selenium}

而后运行它。啊,出错了;看来这里有点问题。

test

原来是验证码的问题。这个可模拟不了……只好做弊了嘿嘿。在测试模式中,咱们可须要把任何针对验证码的输入都当作正确的。而在测试模式下,框架的id是test。因此修改掉yabe/app/controllers/Application.javapostComment action来跳过测试模式下的验证:

…
if(!Play.id.equals("test")) {
    validation.equals(code, Cache.get(randomID)).message("Invalid code. Please type it again");
}
…

如今修改下测试用例。验证码那一栏就随便乱写好了:

…
type('author', 'Me')
type('code', 'XXXXX')
clickAndWait('css=input[type=submit]')
…

而后从新运行测试,这下应该经过了。

评估代码覆盖率

固然咱们尚未完成应用所需的全部测试用例。可是对于咱们的教程来讲已经足够了。在现实的应用中,咱们怎么知道是否已经写了足够的测试用例?咱们须要一个代码覆盖率的概念。

Cobertura 模块使用Cobertura工具生成代码覆盖率报告。使用install命令安装这个模块:

play install cobertura-{version}

咱们仅需在测试模式下启动这个模块。因此在application.conf文件下添加这一行:

# Import the cobertura module in test mode
%test.module.cobertura=${play.path}/modules/cobertura

如今在测试模式下从新启动应用,打开http://localhost:9000/@tests,选中全部测试并运行。应该是绿光满面的节奏。

all green

在全部的测试结束后,中止应用,cobertura将生成代码覆盖率报告。接着你能够在浏览器打开yabe/test-result/code-coverage/index.html,看一下那份报告。

report

若是从新启动应用,你也能够在http://localhost:9000/@cobertura看到它。

如你所见,咱们远远没有完成对应用的全面测试。一个好的测试覆盖率应该尽可能达到100%,即便检查全部的代码是几乎不可能的。毕竟咱们有时候不得不在测试模式下作一些变通,正如咱们曾对验证码作过的同样。

相关文章
相关标签/搜索