咱們已經完成了咱們想要建立的博客引擎。不過這個項目還沒有徹底結束。爲了保證代碼的質量,咱們須要添加更多的測試。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
如今,咱們能夠對應用的所有功能進行一樣的測試,但這並非測試一個基於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。
運行它。(經過在新的標籤頁打開連接,你能夠在一個不一樣的窗口中運行)。
如今咱們開始測試評論框。添加一個新的#{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}
而後運行它。啊,出錯了;看來這裏有點問題。
原來是驗證碼的問題。這個可模擬不了……只好做弊了嘿嘿。在測試模式中,咱們可須要把任何針對驗證碼的輸入都當作正確的。而在測試模式下,框架的id是test
。因此修改掉yabe/app/controllers/Application.java
的postComment
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,選中全部測試並運行。應該是綠光滿面的節奏。
在全部的測試結束後,中止應用,cobertura將生成代碼覆蓋率報告。接着你能夠在瀏覽器打開yabe/test-result/code-coverage/index.html
,看一下那份報告。
若是從新啓動應用,你也能夠在http://localhost:9000/@cobertura看到它。
如你所見,咱們遠遠沒有完成對應用的全面測試。一個好的測試覆蓋率應該儘可能達到100%,即便檢查全部的代碼是幾乎不可能的。畢竟咱們有時候不得不在測試模式下作一些變通,正如咱們曾對驗證碼作過的同樣。