1

我有几个我生成并稍作修改的 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)or expect(Attendance.save()).andReturn(testAttendance),这样我就不必在我的 setUp 方法中创建关联对象的网络,这是验证正在被操作的域对象所必需的控制器。

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

4

2 回答 2

1

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

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

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

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

于 2013-10-22T22:20:41.710 回答
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)对于设置测试中真正需要的值非常有用。我希望我做对了整个事情,我可以提供帮助。

于 2013-10-22T22:21:52.007 回答