【问题标题】:Grails 2.0 Unit Testing Custom Tag LibGrails 2.0 单元测试自定义标签库
【发布时间】:2012-01-30 22:25:32
【问题描述】:

我编写了一个自定义标签库,以便我可以轻松地显示对象的属性。它允许我打电话

<g:property label="Name" property="${user.name}"/>

这使我的观点保持简短和一致,并让我能够快速做出更改。我的taglib代码如下:

def property = {attrs, body ->
    def startingHtml = "..."
    def endingHtml = "..."

    out << startingHtml
    renderField(attrs.property)
    out << endingHtml
}

def renderField(property) {
    if (property instanceof Collection) {
        property.each { out << it + "</br>" }
    } else if(property instanceof Address){
        renderAddress(property)
    } else {
        out << property
    }
}

def renderAddress(address) {
    out << "Address Render Logic Here"
}

我正在尝试围绕此代码添加一些单元测试,因为其中包含逻辑。使用此处找到的示例 (http://grails.org/doc/latest/guide/testing.html#unitTestingTagLibraries) 我开始添加一些测试。我的标签当前处理的前两个场景是字符串和集合,我能够正确测试(下面的前两个测试)。我需要测试的最后一个场景是一个地址对象(它只是一个带有字符串属性的 POGO)。我似乎找不到一种方法来测试将对象作为属性传递到标签库中。

@TestFor(PropertyTagLib)
class PropertyTagLibTests {

@Test
void propertyTagShouldRenderPropertyInsideOfTDWhenPropertyIsAString() {
    String result = applyTemplate('<g:property label="something" property="someTextValue"/>').trim()

    assert result.contains('someTextValue')
}

@Test
void propertyTagShouldRenderList() {
    String result = applyTemplate('g:property label="something" property="[\"one\", \"two\", \"three\"]"/>').trim()

    assert result.contains("one</br>two</br>three</br>")
}

@Test
void propertyTagShouldRenderPropertyInsideOfTDWhenPropertyIsAnAddress() {
    def address = new Address(line1: "Line 1")
    String result = applyTemplate('<g:property label="something" property="${address}"/>').trim()

    assert result.contains("Address Render Logic Here")
}
}

当属性之一是对象时,如何测试我的 taglib?

【问题讨论】:

  • 我猜我不确定。我最初的答案只是猜测的危险,但除此之外我没有任何建议:/

标签: unit-testing grails taglib


【解决方案1】:

applyTemplate() 的声明如下:

String applyTemplate(String contents, Map model = [:])

标签参数通过model传递。

您的测试可能如下所示:

@Test
void propertyTagShouldRenderPropertyInsideOfTDWhenPropertyIsAnAddress() {
    String result = applyTemplate('<g:property label="something" property="${address}"/>', [address : new Address(line1: "Line 1")]).trim()

    assert result.contains("Address Render Logic Here")
}

【讨论】:

  • 每个人都注意传递给applyTemplate的字符串中的单引号,如果你不这样做,你需要转义$
【解决方案2】:

所以我通过“切断中间人”并绕过applyTemplate() 并直接进入执行逻辑的方法来解决这个问题。这不是很理想,原因有两个: 1)我不是断言属性标签与renderField挂钩,但希望我的其他测试仍然使用applyTemplate()确保这一点。 2)在现实世界中,TagLib 中的out 是一个输出编写器,在我的测试中,我将它创建为一个列表(我可以这样做,因为你可以做任何左移操作就足够了)。

我喜欢使用列表的原因是它有助于维护顺序。

@Test
void renderFieldShouldRenderAddress() {
    def address = new Address(line1: "Line 1", line2: "Line 2", line3: "Line 3",
        city: "City", state: "ST", zipCode: "12345", country: "USA",
        buildingNumber: null, buildingName: null, roomNumber: null
        )
    def tagLib = new PropertyTagLib()
    def results = []
    tagLib.metaClass.getOut = {
        results
    }

    tagLib.renderField(address)

    assert "Line 1" == results[0]
    assert "<br />" == results[1]
    assert "Line 2" == results[2]
    assert "<br />" == results[3]
    assert "Line 3" == results[4]
    assert "<br />" == results[5]
    assert "City, ST 12345" == results[6]
    assert "<br />" == results[7]
    assert "USA" == results[8]
    assert "<br />" == results[9]
    assert 10 == results.size()
}

有什么想法吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-13
    • 2011-11-05
    • 1970-01-01
    相关资源
    最近更新 更多