在解決測試數(shù)據(jù)庫支持代碼的困擾時(shí),Java 開發(fā)人員經(jīng)常使用 mock 對象而不是實(shí)際的數(shù)據(jù)庫代碼。Mock 對象設(shè)置起來比較難,通常難于理解,而且對于在數(shù)據(jù)庫環(huán)境中工作的代碼,也無法提供良好的理解。Ruby on Rails 支持不同的方式。
有三個(gè)問題影響了對數(shù)據(jù)庫支持代碼的測試。它們都與兩個(gè)特性有關(guān):性能和重復(fù)性。與內(nèi)存中的操作相比較,數(shù)據(jù)庫調(diào)用的性能是非常低的。如果測試運(yùn)行需要太長時(shí)間,那么您可能不想運(yùn)行它們了。另一個(gè)問題是一個(gè)測試用例對另一個(gè)測試用例的影響。因?yàn)閿?shù)據(jù)庫調(diào)用在性質(zhì)上是持續(xù)的,所以要把一個(gè)測試在數(shù)據(jù)庫中的變化與另一個(gè)數(shù)據(jù)庫中的隔離開。后的問題是前兩個(gè)問題的組合。為了讓數(shù)據(jù)庫測試用例可重復(fù)而增加設(shè)置和拆卸的負(fù)擔(dān)時(shí)(為每個(gè)新的測試用例添加記錄、運(yùn)行測試并刪除這些記錄),帶來的開銷可能是讓人無法接受的。與這種開銷相比,測試用例開銷簡直是小巫見大巫。
Ruby on Rails 用 fixture 和事務(wù)回滾來幫助解決這些問題。在 Rails 中,一個(gè) fixture 是一個(gè)包含測試用例數(shù)據(jù)的文件。在創(chuàng)建這個(gè)簡單應(yīng)用程序時(shí),同時(shí)還創(chuàng)建了一個(gè)開發(fā)數(shù)據(jù)庫和一個(gè)測試數(shù)據(jù)庫。創(chuàng)建開發(fā)數(shù)據(jù)庫是很正常的;但是您可能不想讓生產(chǎn)代碼和開發(fā)環(huán)境共享同一個(gè)數(shù)據(jù)庫。而創(chuàng)建測試數(shù)據(jù)庫因?yàn)榱硪粋(gè)原因也很重要。每個(gè)測試都在測試用例開始時(shí)裝入 fixture 中的測試數(shù)據(jù)。然后,測試用例對數(shù)據(jù)庫進(jìn)行修改,并測試這些修改的結(jié)果。后,Rails 回滾這些變化,將數(shù)據(jù)庫返回到測試方法運(yùn)行之前的狀態(tài)。
現(xiàn)在要制作一個(gè)測試 fixture 并為它編寫一個(gè)測試。請編輯 test/fixtures/trails.yml 文件,添加一個(gè)記錄,如清單 13 所示:
清單 13. 添加記錄
first:
id: 1
name: "Emma Long"
description: "A real bike breaker."
difficulty: "hard"
another:
id: 2
name: "Bear Creek"
description: "Too many downed trees."
difficulty: "easy"
清單 13 使用叫做 YAML 的語言,這個(gè)語言描述結(jié)構(gòu)化的數(shù)據(jù)(請參閱 參考資料)。此文件對空格很敏感,所以該當(dāng)用空格代替制表符并完全按原樣鍵入數(shù)據(jù)項(xiàng)時(shí),請確保刪除了所有尾部空格。
同樣,還要把這個(gè)測試用例添加到 trails_test.rb 中:
def test_find
assert_equal "Emma Long", Trail.find(1).name
assert_equal "easy", Trail.find(2).difficulty
end
同樣,可以用 5 個(gè) passing 斷言運(yùn)行這些測試。如果您愿意,還可以按名稱引用每個(gè) fixture。例如,要根據(jù)名為 first 的 fixture 來創(chuàng)建對象,可以使用 Ruby 代碼 trails[:first]。讓 fixture 對所有測試用例或只對需要它們的測試用例可用,這極大地簡化了創(chuàng)建或毀壞數(shù)據(jù)庫數(shù)據(jù)所需要的代碼。
在 Java 編程中測試
知道了測試在其他語言中如何發(fā)生,可以改進(jìn)在 Java 平臺上進(jìn)行測試的方式。具體地說,使用這些想法中的一項(xiàng)或多項(xiàng)可以對測試產(chǎn)生顯著而直接的影響:
可以把測試用例的生成添加到任何現(xiàn)有代碼生成當(dāng)中。Ruby on Rails 通過在默認(rèn)情況下創(chuàng)建一些簡單的測試用例來取得了巨大優(yōu)勢,您也可以這么做。
可以用事務(wù)-回滾技術(shù)讓數(shù)據(jù)支持的測試運(yùn)行得更快。Spring 框架有一些現(xiàn)有的攔截器,可以讓這項(xiàng)技術(shù)易于使用。
實(shí)際上可以用動(dòng)態(tài)語言驅(qū)動(dòng)測試。Jython、Ruby 和 Groovy 是三個(gè)實(shí)際可能。
如果覺得愿意采用其他語言進(jìn)行測試,那么可以使用某種 JVM 語言,例如 JRuby(請參閱 參考資料)。JRuby 還沒有高級到可以運(yùn)行 Ruby on Rails,但是它是 Java 應(yīng)用程序卓越的測試平臺。只是作為嘗試,JRuby 的開發(fā)人員 Charles O'Nutter 提供了以下測試 EJB 的示例:
清單 14. 用 JRuby 測試 EJB 組件
require 'test/unit'
require 'java'
include_class "my.pkg.EJBHomeFactory"
class TestMyBean < Test::Unit::TestCase
def test_finder
wh = EJBHomeFactory.widget_home
w = wh.find_by_color("blue")
assert_not_nil(w)
end
def test_widget
wh = EJBHomeFactory.widget_home
w = wh.find_by_name ("superWidget")
assert_equal("blue", w.color)
assert_equal(14, w.id)
end
end
可以看到,用 Ruby 編寫執(zhí)行 Java 代碼的測試用例實(shí)際上非常容易。在這個(gè)示例中,Ruby 代碼發(fā)現(xiàn)一個(gè) EJB 組件,并為用戶返回的 bean 提供了一些斷言。測試用例當(dāng)然比多數(shù) Java 測試都容易,使用 Ruby 編寫測試用例是一個(gè)獲得更高的生產(chǎn)率和速率的一種好方法。我還看到針對 Jython 或 Groovy 的類似策略。