【问题标题】:how to get golang to test a multiline output matches如何让golang测试多行输出匹配
【发布时间】:2019-07-11 17:00:59
【问题描述】:

我有以下代码生成一些字符串输出:

package formatter

import (
    "bytes"
    "log"
    "text/template"

    "github.com/foo/bar/internal/mapper"
)

// map of template functions that enable us to identify the final item within a
// collection being iterated over.
var fns = template.FuncMap{
    "plus1": func(x int) int {
        return x + 1
    },
}

// Dot renders our results in dot format for use with graphviz
func Dot(results []mapper.Page) string {
    dotTmpl := `digraph sitemap { {{range .}}
  "{{.URL}}"
    -> { {{$n := len .Anchors}}{{range  $i, $v := .Anchors}}
      "{{.}}"{{if eq (plus1 $i) $n}}{{else}},{{end}}{{end}}
    } {{end}}
}`

    tmpl, err := template.New("digraph").Funcs(fns).Parse(dotTmpl)
    if err != nil {
        log.Fatal(err)
    }

    var output bytes.Buffer
    if err := tmpl.Execute(&output, results); err != nil {
        log.Fatal(err)
    }

    return output.String()
}

它生成如下输出:

digraph sitemap {
  "http://www.example.com/"
    -> {
      "http://www.example.com/foo",
      "http://www.example.com/bar",
      "http://www.example.com/baz"
    }
}

以下是对此功能的测试...

package formatter

import (
    "testing"

    "github.com/foo/bar/internal/mapper"
)

func TestDot(t *testing.T) {
    input := []mapper.Page{
        mapper.Page{
            URL: "http://www.example.com/",
            Anchors: []string{
                "http://www.example.com/foo",
                "http://www.example.com/bar",
                "http://www.example.com/baz",
            },
            Links: []string{
                "http://www.example.com/foo.css",
                "http://www.example.com/bar.css",
                "http://www.example.com/baz.css",
            },
            Scripts: []string{
                "http://www.example.com/foo.js",
                "http://www.example.com/bar.js",
                "http://www.example.com/baz.js",
            },
        },
    }

    output := `digraph sitemap {
      "http://www.example.com/"
          -> {
              "http://www.example.com/foo",
              "http://www.example.com/bar",
              "http://www.example.com/baz"
      }
    }`

    actual := Dot(input)

    if actual != output {
        t.Errorf("expected: %s\ngot: %s", output, actual)
    }
}

失败并出现以下错误(与输出格式间距有关)...

--- FAIL: TestDot (0.00s)
    format_test.go:43: expected: digraph sitemap {
                  "http://www.example.com/"
                          -> {
                                  "http://www.example.com/foo",
                                  "http://www.example.com/bar",
                                  "http://www.example.com/baz"
              }
                }
        got: digraph sitemap { 
          "http://www.example.com/"
            -> { 
              "http://www.example.com/foo",
              "http://www.example.com/bar",
              "http://www.example.com/baz"
            } 
        }

我尝试调整我的测试 output 变量,以便间距与实际代码实际输出的内容保持一致。那没用。

我还尝试在我的输出变量和实际输出的内容上使用strings.Replace(),奇怪的是我的函数的输出(即使它是通过strings.Replace 传递的,仍然是多行的(所以测试会失败)?

有人知道如何使输出保持一致以进行代码验证吗?

谢谢。

更新

我尝试了@icza 建议的方法,但它仍然未能通过测试,尽管测试中的输出看起来更像是预期的:

=== RUN   TestDot
--- FAIL: TestDot (0.00s)
    format_test.go:65: expected: digraph sitemap {
          "http://www.example.com/"
            -> {
              "http://www.example.com/foo",
              "http://www.example.com/bar",
              "http://www.example.com/baz"
            }
        }
        got: digraph sitemap { 
          "http://www.example.com/"
            -> { 
              "http://www.example.com/foo",
              "http://www.example.com/bar",
              "http://www.example.com/baz"
            }
        }

【问题讨论】:

    标签: string templates go testing formatting


    【解决方案1】:

    如果要忽略格式,可以使用strings.Fields

    output := strings.Fields(`digraph sitemap {
      "http://www.example.com/"
          -> {
              "http://www.example.com/foo",
              "http://www.example.com/bar",
              "http://www.example.com/baz"
      }
    }`)
    
    actual := strings.Fields(Dot(input))
    
    if !equal(output,actual) {
        // ...
    }
    

    其中 equal 是一个比较两个切片的简单函数。

    【讨论】:

      【解决方案2】:

      最简单的解决方案是在指定预期输出时在测试中使用相同的缩进(与您在模板中使用的相同)。

      你有:

      output := `digraph sitemap {
        "http://www.example.com/"
            -> {
                "http://www.example.com/foo",
                "http://www.example.com/bar",
                "http://www.example.com/baz"
        }
      }`
      

      改成:

          output := `digraph sitemap {
        "http://www.example.com/"
          -> {
            "http://www.example.com/foo",
            "http://www.example.com/bar",
            "http://www.example.com/baz"
          }
      }`
      

      请注意,例如最后一行没有缩进。当您使用原始字符串文字时,包括缩进字符在内的每个字符都是文字的一部分。

      创建正确的、未缩进的原始字符串文字的步骤

      毕竟,这完全是一个非编码问题,而是编辑器自动格式化和定义原始字符串文字的问题。一个简单的方法是首先编写一个空的原始字符串文字,添加一个空行并清除编辑器插入的自动缩进:

          output := `
      `
      

      当你有这个时,在结束反引号之前复制粘贴正确的输入,例如:

          output := `
      digraph sitemap {
        "http://www.example.com/"
          -> {
            "http://www.example.com/foo",
            "http://www.example.com/bar",
            "http://www.example.com/baz"
          }
      }`
      

      最后一步,从原始字符串文字的第一行删除换行符,您就有了正确的原始字符串文字:

          output := `digraph sitemap {
        "http://www.example.com/"
          -> {
            "http://www.example.com/foo",
            "http://www.example.com/bar",
            "http://www.example.com/baz"
          }
      }`
      

      一旦你有了这个,运行gofmt或编辑器的自动格式化就不会再搞砸了。

      更新:

      我检查了你更新的测试结果,在你得到的结果中,第一行后面有一个空格:digraph sitemap {,第三行后面还有一个空格:-> {,但你没有添加那些你预期的输出。要么将它们添加到您的预期输出中,要么从模板中删除这些空格!比较字符串时,会按字节进行比较,每个字符(包括空格)都很重要。

      要从模板中删除那些多余的空格:

          dotTmpl := `digraph sitemap { {{- range .}}
        "{{.URL}}"
          -> { {{- $n := len .Anchors}}{{range  $i, $v := .Anchors}}
            "{{.}}"{{if eq (plus1 $i) $n}}{{else}},{{end}}{{end}}
          } {{end}}
      }`
      

      注意{{- 的使用。这是给trim spaces around template actions的,这是在Go 1.6中添加的。

      【讨论】:

      • 是的,这是我尝试过的,但我仍然失败了 :-( 它也感觉很复杂(因为我认为我已经匹配了,但显然我不希望它失败)所以我认为我更喜欢'leaf bebop'描述的strings.Fields方法。
      • 当指定output 变量时,第一行将缩进。这不是问题,重要的是反引号之间的内容。因此,当您指定预期输出时,代码编辑器不得缩进后续行。编辑器足够聪明,不会在原始字符串文字中自动缩进内容。
      • 这很容易出错,就像你在反引号之间复制粘贴一个有效的输出一样,代码编辑器会错误地格式化它(自动缩进多行)。最简单的方法是编写变量声明,例如output := ``,然后在第一个反引号后按 Enter,清除缩进,然后复制粘贴有效输出(最后删除第一个换行符)。
      • 毕竟,这完全是一个非编码问题,而是编辑器自动格式化和定义原始字符串文字的问题。
      • 感谢更新的答案。不幸的是,即使按照您的明确步骤,它仍然会失败?我不相信我的编辑器对空格做任何事情,并且测试中的失败输出看起来像一个匹配点。
      【解决方案3】:

      问题是有一个额外的空间。在{ 之后的格式化文本中,这似乎是您的问题。您可以通过将格式字符串更改为此来修复它

      `digraph sitemap {{{range .}}
        "{{.URL}}"
          -> {{{$n := len .Anchors}}{{range  $i, $v := .Anchors}}
            "{{.}}"{{if eq (plus1 $i) $n}}{{else}},{{end}}{{end}}
          }{{end}}
      }`
      

      【讨论】:

        猜你喜欢
        • 2015-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-26
        • 1970-01-01
        • 1970-01-01
        • 2019-03-17
        相关资源
        最近更新 更多