0

我有一个域类

class File {
    String name
    String path

    static constraints = {
        name nullable:false
        path nullable:false
    }
}

生成的控制器

class FileController {

static allowedMethods = [create: ['GET', 'POST'], edit: ['GET', 'POST'], delete: 'POST']

def index() {
    redirect action: 'list', params: params
}

def list() {
    params.max = Math.min(params.max ? params.int('max') : 10, 100)
    [fileInstanceList: File.list(params), fileInstanceTotal: File.count()]
}

def create() {
    switch (request.method) {
    case 'GET':
        [fileInstance: new File(params)]
        break
    case 'POST':
        def fileInstance = new File(params)
        if (!fileInstance.save(flush: true)) {
            render view: 'create', model: [fileInstance: fileInstance]
            return
        }

        flash.message = message(code: 'default.created.message', args: [message(code: 'file.label', default: 'File'), fileInstance.id])
        redirect action: 'show', id: fileInstance.id
        break
    }
}

def show() {
    def fileInstance = File.get(params.id)
    if (!fileInstance) {
        flash.message = message(code: 'default.not.found.message', args: [message(code: 'file.label', default: 'File'), params.id])
        redirect action: 'list'
        return
    }

    [fileInstance: fileInstance]
}

def edit() {
    switch (request.method) {
    case 'GET':
        def fileInstance = File.get(params.id)
        if (!fileInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'file.label', default: 'File'), params.id])
            redirect action: 'list'
            return
        }

        [fileInstance: fileInstance]
        break
    case 'POST':
        def fileInstance = File.get(params.id)
        if (!fileInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'file.label', default: 'File'), params.id])
            redirect action: 'list'
            return
        }

        if (params.version) {
            def version = params.version.toLong()
            if (fileInstance.version > version) {
                fileInstance.errors.rejectValue('version', 'default.optimistic.locking.failure',
                          [message(code: 'file.label', default: 'File')] as Object[],
                          "Another user has updated this File while you were editing")
                render view: 'edit', model: [fileInstance: fileInstance]
                return
            }
        }

        fileInstance.properties = params

        if (!fileInstance.save(flush: true)) {
            render view: 'edit', model: [fileInstance: fileInstance]
            return
        }

        flash.message = message(code: 'default.updated.message', args: [message(code: 'file.label', default: 'File'), fileInstance.id])
        redirect action: 'show', id: fileInstance.id
        break
    }
}

def delete() {
    def fileInstance = File.get(params.id)
    if (!fileInstance) {
        flash.message = message(code: 'default.not.found.message', args: [message(code: 'file.label', default: 'File'), params.id])
        redirect action: 'list'
        return
    }

    try {
        fileInstance.delete(flush: true)
        flash.message = message(code: 'default.deleted.message', args: [message(code: 'file.label', default: 'File'), params.id])
        redirect action: 'list'
    }
    catch (DataIntegrityViolationException e) {
        flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'file.label', default: 'File'), params.id])
        redirect action: 'show', id: params.id
    }
}

和生成的测试用例

@TestFor(FileController)
@Mock(File)
class FileControllerTests {


def populateValidParams(params) {
  assert params != null
  params["name"] = 'someValidName'
  params["path"] = 'someValidPath'
}

void testIndex() {
    controller.index()
    assert "/file/list" == response.redirectedUrl
}

void testList() {

    def model = controller.list()

    assert model.fileInstanceList.size() == 0
    assert model.fileInstanceTotal == 0
}

void testCreate() {
   def model = controller.create()

   assert model.fileInstance != null
}

void testSave() {
    controller.save()

    assert model.fileInstance != null
    assert view == '/file/create'

    response.reset()

    populateValidParams(params)
    controller.save()

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

void testShow() {
    controller.show()

    assert flash.message != null
    assert response.redirectedUrl == '/file/list'


    populateValidParams(params)
    def file = new File(params)

    assert file.save() != null

    params.id = file.id

    def model = controller.show()

    assert model.fileInstance == file
}

void testEdit() {
    controller.edit()

    assert flash.message != null
    assert response.redirectedUrl == '/file/list'


    populateValidParams(params)
    def file = new File(params)

    assert file.save() != null

    params.id = file.id

    def model = controller.edit()

    assert model.fileInstance == file
}

void testUpdate() {
    controller.update()

    assert flash.message != null
    assert response.redirectedUrl == '/file/list'

    response.reset()


    populateValidParams(params)
    def file = new File(params)

    assert file.save() != null

    // test invalid parameters in update
    params.id = file.id
    params["name"] = null
    params["path"] = null

    controller.update()

    assert view == "/file/edit"
    assert model.fileInstance != null

    file.clearErrors()

    populateValidParams(params)
    controller.update()

    assert response.redirectedUrl == "/file/show/$file.id"
    assert flash.message != null

    //test outdated version number
    response.reset()
    file.clearErrors()

    populateValidParams(params)
    params.id = file.id
    params.version = -1
    controller.update()

    assert view == "/file/edit"
    assert model.fileInstance != null
    assert model.fileInstance.errors.getFieldError('version')
    assert flash.message != null
}

void testDelete() {
    controller.delete()
    assert flash.message != null
    assert response.redirectedUrl == '/file/list'

    response.reset()

    populateValidParams(params)
    def file = new File(params)

    assert file.save() != null
    assert File.count() == 1

    params.id = file.id

    controller.delete()

    assert File.count() == 0
    assert File.get(file.id) == null
    assert response.redirectedUrl == '/file/list'
}
}

我为通过和失败的测试用例添加了正确的参数,但仍然存在运行时错误,并且控制器中生成的代码与测试用例中生成的代码不一致。测试用例调用控制器中不存在的方法。

这是错误代码/堆栈跟踪

groovy.lang.MissingMethodException: No signature of method: FileController.update() is applicable for argument types: () values: []
Possible solutions: create(), putAt(java.lang.String, java.lang.Object), delete(), edit(), isCase(java.lang.Object), split(groovy.lang.Closure)
    at FileControllerTests.testUpdate(FileControllerTests.groovy:98)

所以基本上没有称为更新的控制器方法,因为用于编辑和更新日期的控制器已被组合并使用 request.method = 'POST' 或 'GET' 来放松适当的操作。

所以基本上我的问题是如何生成正确的单元测试用例?还是我完全错过了其他东西?

我正在使用 grails 2.1.1

4

2 回答 2

1

您那里的代码看起来像样板脚手架模板,所以我假设您在某些时候针对 File 域类运行 generate-all。这样做可能会创建您的 FileController 和相应的 FileControllerTest 以及所有“crud”操作/测试。

只是在这里猜测一下,但是在某些时候,您可能已经删除了 FileController 中的更新操作,但将 FileControllerTest 留在了原处,这让您

//in FileControllerTests
void testUpdate() {
    controller.update()
    ...
}

只需更新您的测试类 - 如果您认为以后需要它,请删除 testUpdate 或将其注释掉。

于 2013-07-16T23:14:18.220 回答
0

因此,当我使用 twitter 引导脚手架文件更新模板文件时,就会出现这种差异。他们在脚手架源代码中没有更新的 Test.groovy 文件。

我必须更新 Test.groovy 文件以对应新的 Controller.groovy 文件。

于 2013-07-22T22:25:08.457 回答