Возможно ли реализовать единичный тест против такого картографирования url?
"500" (controller: 'error', action: 'handle', exception: MyCustomException)
Я попытался написать такой unit тест
@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
Если я удалю исключение: MyCustomException из UrlMapping.groovy и от модульного теста, он работает. Но я не могу этого сделать.
Я знаю, что прошло почти 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)
}
}