Grails 2.2.2 UrlMappings测试,但有例外

时间:2015-02-05 15:48:22

标签: java unit-testing grails

是否可以针对此类网址映射实施单元测试?

"500" (controller: 'error', action: 'handle', exception: MyCustomException)

我试过写这样的单元测试

@TestFor(UrlMappings)
@Mock(ErrorController)
class UrlMappingsTest {

    void test() {
        assertForwardUrlMapping(500, controller: "error", action: "handle", exception: MyCustomException)


    }

}

但获得了junit.framework.AssertionFailedError: url '500' did not match any mappings

如果我删除了异常:来自UrlMapping.groovy的MyCustomException和单元测试它可以正常工作。但我不能这样做。

1 个答案:

答案 0 :(得分:0)

我知道它已经差不多2年但我昨天也遇到了这个问题,虽然使用Grails 2.4.4,所以我会在这里发布一个解决方案以防万一有人碰到这个问题。

好像你不得不编写测试一样,编写测试比编写实际代码需要多1000%的时间更令人不安! :)

无论如何,问题是UrlMappingsUnitTestMixin无法处理这种情况。

这里报告了一个官方错误: https://github.com/grails/grails-core/issues/10226并在上个月推出了一项解决方案。

如果您想使用Grails 2.4.4中的修复程序,您可以创建一个mixin UrlMappingsUnitTestMixinBugFix,然后在UrlMappingsTest中使用它。

UrlMappingsUnitTestMixin.groovy

package com.example.util.test

import grails.util.Holders
import junit.framework.AssertionFailedError
import org.codehaus.groovy.grails.commons.ControllerArtefactHandler
import org.codehaus.groovy.grails.commons.GrailsControllerClass
import org.codehaus.groovy.grails.web.mapping.UrlMappingsHolder

import static junit.framework.Assert.assertEquals

/**
 * Methods below are copied from {@link grails.test.mixin.web.UrlMappingsUnitTestMixin}
 *
 * <p>This method is here because the {@link grails.test.mixin.web.UrlMappingsUnitTestMixin} in Grails 2.4.4 has a bug and this code fixes it.
 * <p>Link to the bug: <a href="https://github.com/grails/grails-core/issues/10226">here</a>.
 *
 * <p>To use this class just write UrlMappingsTest as per Grails guidelines and add a static code block to the Test:
 * <p>
 * <code>
 *  static {
 *      UrlMappingsTest.mixin(UrlMappingsUnitTestMixinBugFix)
 *  }
 * </code>
 */
class UrlMappingsUnitTestMixinBugFix {

    void assertForwardUrlMapping(assertions, url) {
        assertForwardUrlMapping(assertions, url, null)
    }

    void assertForwardUrlMapping(assertions, url, paramAssertions) {

        def assertionKeys = ["controller", "action", "view"]
        final String KEY_EXCEPTION = 'exception'

        UrlMappingsHolder mappingsHolder = Holders.applicationContext.getBean("grailsUrlMappingsHolder", UrlMappingsHolder)
        if (assertions.action && !assertions.controller) {
            throw new AssertionFailedError("Cannot assert action for url mapping without asserting controller")
        }

        if (assertions.controller) assertController(assertions.controller, url)
        if (assertions.action) assertAction(assertions.controller, assertions.action, url)
        if (assertions.view) assertView(assertions.controller, assertions.view, url)

        def mappingInfos
        if (url instanceof Integer) {
            mappingInfos = []

            // -------- START FIX --------

            // -------- OLD CODE (below) --------
            // def mapping = mappingsHolder.matchStatusCode(url)
            // if (mapping) mappingInfos << mapping

            // -------- FIXED CODE (below) --------
            def mapping
            if (assertions."$KEY_EXCEPTION") {
                mapping = mappingsHolder.matchStatusCode(url, assertions."$KEY_EXCEPTION" as Throwable)
            } else {
                mapping = mappingsHolder.matchStatusCode(url)
            }
            if (mapping) mappingInfos << mapping

            // -------- END FIX --------

        } else {
            mappingInfos = mappingsHolder.matchAll(url)
        }

        if (mappingInfos.size() == 0) throw new AssertionFailedError("url '$url' did not match any mappings")

        def mappingMatched = mappingInfos.any { mapping ->
            mapping.configure(webRequest)
            for (key in assertionKeys) {
                if (assertions.containsKey(key)) {
                    def expected = assertions[key]
                    def actual = mapping."${key}Name"

                    switch (key) {
                        case "controller":
                            if (actual && !getControllerClass(actual)) return false
                            break
                        case "view":
                            if (actual[0] == "/") actual = actual.substring(1)
                            if (expected[0] == "/") expected = expected.substring(1)
                            break
                        case "action":
                            if (key == "action" && actual == null) {
                                final controllerClass = getControllerClass(assertions.controller)
                                actual = controllerClass?.defaultAction
                            }
                            break
                    }

                    assertEquals("Url mapping $key assertion for '$url' failed", expected, actual)
                }
            }
            if (paramAssertions) {
                def params = [:]
                paramAssertions.delegate = params
                paramAssertions.resolveStrategy = Closure.DELEGATE_ONLY
                paramAssertions.call()
                params.each { name, value ->
                    assertEquals("Url mapping '$name' parameter assertion for '$url' failed", value, mapping.params[name])
                }
            }
            return true
        }

        if (!mappingMatched) throw new IllegalArgumentException("url '$url' did not match any mappings")
    }

    private GrailsControllerClass getControllerClass(controller) {
        return grailsApplication.getArtefactByLogicalPropertyName(ControllerArtefactHandler.TYPE, controller)
    }

}

UrlMappingsTest.groovy

import com.example.controller.ErrorController
import com.example.util.test.UrlMappingsUnitTestMixinBugFix
import grails.test.mixin.Mock
import grails.test.mixin.TestFor

@TestFor(UrlMappings)
@Mock(ErrorController)
class UrlMappingsTest {


static {
    UrlMappingsTest.mixin(UrlMappingsUnitTestMixinBugFix)
}


void test() {

        assertForwardUrlMapping(500, controller: "error", action: "handle", exception: MyCustomException)
    }

}