The sources
/src/trip-planner2/test/integration/HotelStayTests.groovy and
/src/trip-planner2/test/unit/HotelStayTests.groovy are
containing both a class of the name HotelStayTests.
@ line 3, column 1.
class HotelStayTests extends GroovyTestCase {
^
输入 grails run-app。如果您尝试在留空 hotel 字段的情况下创建一个 HotelStay,将收到如图 6 所示的错误消息:
图 6. 空字段的默认错误消息我敢保证您的用户会喜欢这个特性,但对默认的错误消息还不是很满意。假设他们稍微改动了一下用户场景:hotel 字段不能留空;如果留空,错误消息会提示 “Please provide a hotel name”。
现在您已经添加了一些定制代码 — 尽管它就像一个定制的 String 那么简单 — 接下来应该添加测试了(当然,编写一个验证用户场景的完整性的测试 — 尽管不涉及到定制代码 — 也是完全可以接受的。
打开 grails-app/i18n/messages.properties 并添加 hotelStay.hotel.blank=Please provide a hotel name。尝试在浏览器中提交一个空 hotel。这时您将看到自己的定制消息,如图 7 所示:
图 7. 显示定制的验证错误消息向 HotelStayTests.groovy 添加一个新测试,检验对空字段的验证是否有效,如清单 9 所示:
清单 9. 测试验证错误
1
2
3
4
5
6
7
8
9
class HotelStayTests extends GroovyTestCase {
void testBlankHotel(){
def h = new HotelStay(hotel:"")
assertFalse "there should be errors", h.validate()
assertTrue "another way to check for errors after you call validate()", h.hasErrors()
}
class HotelStayTests extends GroovyTestCase {
void testBlankHotel(){
def h = new HotelStay(hotel:"")
assertFalse "there should be errors", h.validate()
assertTrue "another way to check for errors after you call validate()", h.hasErrors()
println "\nErrors:"
println h.errors ?: "no errors found"
def badField = h.errors.getFieldError('hotel')
println "\nBadField:"
println badField ?: "hotel wasn't a bad field"
assertNotNull "I'm expecting to find an error on the hotel field", badField
def code = badField?.codes.find {it == 'hotelStay.hotel.blank'}
println "\nCode:"
println code ?: "the blank hotel code wasn't found"
assertNotNull "the blank hotel field should be the culprit", code
}
}
确定类没有通过验证之后,您可以调用 getErrors() 方法(在这里,借助 Groovy 简洁的 getter 语法,它被缩略为 errors),返回一个 org.springframework.validation.BeanPropertyBindingResult。就像 GORM 与 Hibernate 相比是一个瘦 Groovy 层一样,Grails 验证只不过是一个简单的 Spring 验证。
调用 println 的结果不会在命令行上显示,但它们出现在 HTML 报告中,如图 8 所示:
图 8. 查看测试的 println 输出在 HotelStayTests 报告的右下角单击 System.out 链接。
中给人亲切感觉的 Elvis 操作符(转过脸来 — 看见他向后梳起的发型和那双眼睛吗?)是一个缩略的 Groovy 三元操作符。如果 ?: 左边的对象为 null,将使用右边的值。
将 hotel 字段更改为 "Holiday Inn" 并重新运行测试。您将在 HTML 报告中看到另一个 Elvis 输出,如图 9 所示:
图 9. 测试输出中的 Elvis看见 Elvis 之后,不要忘记清空 hotel 字段 — 如果您不希望留下中断的测试的话。
如果仍然显示关于 checkIn 和 checkOut 的验证错误,您不必担心。就这个测试而言,您完全可以忽略它们。但是这表明您不应该仅测试错误是否出现 — 您应该确保特定的 错误被抛出。
注意,我没有断言定制错误消息的确切文本。为什么我上一次关注匹配的字符串(测试 toString 的输出时)而这一次没有关注?toString 方法的定制输出便是上一个测试的目的。这一次,我更关心的是确定验证代码的执行,而不是 Grails 是否正确呈现消息。这表明测试更像一门艺术,而不是科学(如果我想验证准确的消息输出,则应该使用 Web 层测试工具,比如 Canoo WebTest 或 ThoughtWorks Selenium)。