pro*_*ski 2 testing tdd grails unit-testing
这是grails应用程序中的一个简单域类:
class User {
String username
static constraints = {
username unique: true
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:我应该编写单元测试来检查用户名字段是否唯一?
@Test
void cannotCreateMoreThanOneUserWithTheSameUsername() {
new User(username: 'john').save()
def secondUser = new User(username: 'john')
assert !secondUser.validate()
}
Run Code Online (Sandbox Code Playgroud)
我有点怀疑,因为:
如果我按照TDD原则编写User类,那么我应该在实现约束闭包之前编写失败的测试.
另一方面,在域中设置唯一约束是数据模型配置而不是真实逻辑.而且,保存和验证方法在框架中实现.
在我看来,单元测试CRUD方法并不值得,因为Grails开发人员已经对这些方法进行了全面测试.另一方面,单元测试约束很重要,因为约束可能会在应用程序的生命周期中发生变化,并且您希望确保捕获这些更改.您永远不知道可能需要修改哪些业务逻辑来支持所述更改.我喜欢使用Spock,典型的约束测试看起来像这样:
@TestFor(User)
class UserSpec extends ConstraintUnitSpec {
def setup() {
mockForConstraintsTests(User, [new User(username: 'username', emailAddress: 'email@email.com')])
}
@Unroll("test user all constraints #field is #error")
def "test user all constraints"() {
when:
def obj = new User("$field": val)
then:
validateConstraints(obj, field, error)
where:
error | field | val
'blank' | 'username' | ' '
'nullable' | 'username' | null
'unique' | 'username' | 'username'
'blank' | 'password' | ' '
'nullable' | 'password' | null
'maxSize' | 'password' | getLongString(65)
'email' | 'emailAddress' | getEmail(false)
'unique' | 'emailAddress' | 'email@email.com'
'blank' | 'firstName' | ' '
'nullable' | 'firstName' | null
'maxSize' | 'firstName' | getLongString(51)
'blank' | 'lastName' | ' '
'nullable' | 'lastName' | null
'maxSize' | 'lastName' | getLongString(151)
'nullable' | 'certificationStatus' | null
}
}
Run Code Online (Sandbox Code Playgroud)
这是ConstraintUnitSpec基类:
abstract class ConstraintUnitSpec extends Specification {
String getLongString(Integer length) {
'a' * length
}
String getEmail(Boolean valid) {
valid ? "test@wbr.com" : "test@w"
}
String getUrl(Boolean valid) {
valid ? "http://www.google.com" : "http:/ww.helloworld.com"
}
String getCreditCard(Boolean valid) {
valid ? "4111111111111111" : "41014"
}
void validateConstraints(obj, field, error) {
def validated = obj.validate()
if (error && error != 'valid') {
assert !validated
assert obj.errors[field]
assert error == obj.errors[field]
} else {
assert !obj.errors[field]
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我从博客文章中学到的一种技巧.但我现在不记得了.我会寻找它,如果我找到它,我会确定并链接到它.