【问题标题】:how to test method that prints to console in golang?如何测试在golang中打印到控制台的方法?
【发布时间】:2017-11-14 08:37:22
【问题描述】:

我有下一个结构。

package logger

import "fmt"

type IPrinter interface {
    Print(value string)
}

type ConsolePrinter struct{}

func (cp *ConsolePrinter) Print(value string) {
    fmt.Printf("this is value: %s", value)
}

测试覆盖率说我需要测试 ConsolePrinter Print 方法。

我怎样才能覆盖这个方法?

谢谢。

【问题讨论】:

标签: unit-testing go


【解决方案1】:

在@icza 写的评论之后,我在下面写了测试。

func TestPrint(t *testing.T) {
    rescueStdout := os.Stdout
    r, w, _ := os.Pipe()
    os.Stdout = w

    cp := &ConsolePrinter{}
    cp.Print("test")

    w.Close()
    out, _ := ioutil.ReadAll(r)
    os.Stdout = rescueStdout

    if string(out) != "this is value: test" {
        t.Errorf("Expected %s, got %s", "this is value: test", out)
    }
}

我找到了有问题的示例What is the best way to convert byte array to string?

【讨论】:

    【解决方案2】:

    使用Examples 传达函数的用法。

    不要担心超过 100% 的测试覆盖率,尤其是对于简单直接的函数。

    func ExampleHello() {
        fmt.Println("hello")
        // Output: hello
    }
    

    额外的好处是examples 是使用 go doc 工具在生成的文档中输出的。

    【讨论】:

    • 如果我理解的很好,我在例子中就得调用 ConsolePrinter 的打印方法了吧?
    • 尽量不要刻意:)
    • 现在您知道了,但是您已经获得了一段经过记录和测试的代码。请记住,封面只是一个软件指标。无需重复测试即可获得更高的覆盖率。
    • 我明白你说的。尽管如此,我还是想看看是否有办法让这部分代码被测试覆盖。
    • 例如——“当你想向用户记录一个函数时,使用Examples。否则使用测试——通常你需要使用数据提供者来测试函数。这都是相对的。做出你的选择。
    【解决方案3】:

    我建议创建logger 的新实例,其行为与将数据打印到控制台的fmt 方法完全相同。此外,您可以使用其他功能对其进行配置,例如显示文件名、日期等。此类自定义记录器可以作为参数传递给您的服务/实例工厂方法。这将使模拟和测试变得非常容易。

    你的代码

    type Logs interface {
        Println(v ...interface{})
    }
    
    type InstanceToTest struct {
        log Logs
    }
    
    func InstanceToTestFactory(logger Logs) *InstanceToTest {
        return &InstanceToTest{logger}
    }
    
    func (i *InstanceToTest) SomeMethod(a string) {
        i.log.Println(a)
    }
    

    为记录器创建一个模拟

    type LoggerMock struct {
        CalledPrintln []interface{}    
    }
    
    func (l *LoggerMock) Println(v ...interface{}) {
        l.CalledPrintln = append(CalledPrintln, v)
    }
    

    在你的测试中

    func TestInstanceToTestSomeMethod(t *testing.T) {
        l := &LoggerMock{}
        i := InstanceToTestFactory(l)
        a := "Test"
    
        i.SomeMethod(a)
    
        if len(l.CalledPrintln) == 0 || l.CalledPrintln[0] != a {
            t.Error("Not called")
        }
    }
    

    【讨论】:

    • 谢谢,我正在为我正在测试的其他方法执行此操作。
    猜你喜欢
    • 2022-10-12
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 2012-03-04
    • 2014-08-28
    • 1970-01-01
    相关资源
    最近更新 更多