【问题标题】:Grails Mocks: Decoupling Validation from ControllerGrails Mocks:将验证与控制器解耦
【发布时间】:2013-10-22 20:25:28
【问题描述】:

我有几个我生成并稍作修改的 grails 控制器。我正在使用生成的单元测试并让它们通过,但我认为我正在努力做到这一点。这就是我所拥有的。

package edu.liberty.swiper

import grails.test.mixin.*

import org.junit.*

@TestFor(AttendanceController)
@Mock([Attendance, Location, Reason, Person, LocCapMode, GuestContactMode, UserAccount])
class AttendanceControllerTests {

def location
def reason

void setUp() {
    def capMode = new LocCapMode(description: "loc cap mode", username: "testuser").save(failOnError: true)
    def guestMode = new GuestContactMode(description: "Guest Contact Mode", username: "testuser").save(failOnError: true)
    location = new Location(description: "foo", locCapMode: capMode, username: "testuser", guestContactMode: guestMode).save(failOnError: true)
    reason = new Reason(description: "test reason", username: "testuser").save(failOnError: true)
    def person = new Person(firstName: "John", lastName: "Smith", lid: "L12345678", mi: "Q", pidm: 12345).save(failOnError: true)
    def userAccount = new UserAccount(pidm: 12345, username: "testuser").save(failOnError:true)
}

def populateValidParams(params) {
    assert params != null
    params.personId = '12345'
    params.username = "testuser"
    params["location.id"] = location.id
    params["reason.id"] = reason.id
    params.timeIn = new Date()
}

void testIndex() {
    ...
}

void testList() {
    ...
}

void testCreate() {
    ...
}

void testSave() {
    controller.save()

    assert model.attendanceInstance != null
    assert view == '/attendance/create'

    response.reset()

    populateValidParams(params)
    controller.save()

    assert response.redirectedUrl == '/attendance/show/1'
    assert controller.flash.message != null
    assert Attendance.count() == 1
}

void testEdit() {
    ...
}

...

我希望能够动态模拟域对象,即expect(Attendance.save()).andReturn(null)expect(Attendance.save()).andReturn(testAttendance),这样我就不必在我的 setUp 方法中创建验证所需的关联对象网络控制器正在操作的域对象。

我只是看错了吗?似乎我应该能够将控制器逻辑与验证逻辑分离,这样我就可以告诉模拟告诉控制器验证通过或失败。提前致谢。

【问题讨论】:

    标签: unit-testing validation grails grails-orm


    【解决方案1】:

    我认为没有办法告诉模拟控制器处理的某个对象的验证通过或失败,但我可能错了。但据我了解,您主要关心的是创建关联对象网络,对吗?

    在不知道你的控制器是什么样子的情况下,我猜你是通过 ID(例如位置)在控制器中获取所需的域对象并通过 pidm 等加载一个人。

    为了简化所需域对象的创建,您可以使用 .save(validate: false)。 您的 setUp 方法可能如下所示:

    location = new Location().save(validate: false)
    reason = new Reason().save(validate: false)
    

    如果您只需要具有有效 ID 的对象,这就足够了。

    new Person(pidm: 12345).save(validate: false)
    new UserAccount(username: "testuser").save(validate: false)
    

    设置某些字段以便能够使用像 UserAccount.findByUserName() 这样的查找器。

    所以如果你的控制器做了类似的事情

    location = Location.get(params["location.id"])
    reason = Reason.get(params["reason.id"])
    userAccount = UserAccount.findByUserName(params.username)
    ...
    new Attendance(location: location, reason: reason, userAccount: userAccount, ...)
    

    上述行应该满足您的 setUp 方法。

    .save(validate: false) 对于设置测试中真正需要的值非常有用。我希望我做对了整个事情,我可以提供帮助。

    【讨论】:

    • 非常有帮助。谢谢。这正是我所需要的!
    【解决方案2】:

    在模拟单元测试时,您不必拥有包含每个所需值的完整对象图来测试单个域。例如,你可以有这样的东西..

    def department = new Department(name: "Accounting").save(validate: false)
    def user = new User(username: "gdboling", department: department).save()
    

    假设用户只有 2 个必填字段是用户名和部门,但部门可能有许多其他字段无法通过验证,如果您真正需要测试的只是用户,这仍然有效。

    您仍然需要在@Mock 中指定它们,您只是不必填充每个该死的字段。 :)

    【讨论】:

    • 非常有帮助。谢谢。这正是我所需要的!
    猜你喜欢
    • 2012-01-23
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    • 2012-09-10
    • 1970-01-01
    相关资源
    最近更新 更多