dqwh1203
2019-05-31 14:46
浏览 441
已采纳

打开和读取文件的单元测试功能

I am working on learning go with a simple program that is doing some file reading and am working on adding unit testing to my program. I have ran into an issue/question while doing this. I want to unit test the function below and my question is that the function takes a name of the file which is then opened and processed. During testing I do not want to actually pass it a real file. I am wondering is this something I can somehow mock so that I can just pass it a "fake" file and have it process that instead? Thanks!

func openAndReadFile(fileName string) [][]string {
    file, err := os.Open(fileName)
    if err != nil {
        fmt.Printf("Failed to read file: %s", fileName)
    }
    r := csv.NewReader(file)
    lines, err := r.ReadAll()
    if err != nil {
        log.Fatal(err)
    }
    return lines
}

图片转代码服务由CSDN问答提供 功能建议

我正在研究一个简单的程序,该程序正在读取文件并正在向其中添加单元测试。 我的程序。 我在执行此操作时遇到了一个问题。 我想对下面的函数进行单元测试,我的问题是该函数使用文件名,然后打开并处理该文件。 在测试期间,我实际上不想将其传递给真实文件。 我想知道这是我可以以某种方式模拟的东西,以便我可以仅将其传递给“假”文件并由它来处理吗? 谢谢!

  func openAndReadFile(fileName string)[] [] string {
 file,err:= os.Open(fileName)
 if err!= nil {
 fmt  .Printf(“无法读取文件:%s”,fileName)
} 
r:= csv.NewReader(file)
行,如果错误,则err:= r.ReadAll()
!= nil {
  log.Fatal(err)
} 
返回行
} 
   
 
  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • doucan4873 2019-05-31 16:06
    已采纳

    You need to refactor your code and make more suitable for testing.

    Here is how I would do it:

    func openAndReadFile(fileName string) [][]string {
        file, err := os.Open(fileName)
        if err != nil {
            fmt.Printf("Failed to open file: %s", fileName)
        }
        lines, err := readFile(file)
        if err != nil {
            fmt.Printf("Failed to read file: %s", fileName)
        }
        return lines
    }
    
    func readFile(reader io.Reader) ([][]string, error) {
        r := csv.NewReader(reader)
        lines, err := r.ReadAll()
        if err != nil {
            log.Fatal(err)
        }
        return lines, err
    }
    

    Then for testing you can simply use any data structure that implements the io.reader interface. For example, I use a bytes buffer, but you can choose a network connection:

    func TestReadFile(t *testing.T) {
        var buffer bytes.Buffer
        buffer.WriteString("fake, csv, data")
        content, err := readFile(&buffer)
        if err != nil {
            t.Error("Failed to read csv data")
        }
        fmt.Print(content)
    }
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • doudiaozhi6658 2019-05-31 21:38

    The function you have shown is dominated by interactions: Interactions with the file system and interactions with the csv reader. To be sure that these interactions work nicely you will later anyway have to do some integration-testing against the file system and the csv reader. Think about which bugs you are hoping to find, and you will see that bugs are more likely on the interaction level: Is the order of file,err correct, or should it be the other way around? Is nil really the value indicating no error? Do you have to give more arguments to Open? etc.

    Therefore, I would not concentrate on unit-testing this function. However, this function is a good candidate to be mocked to make unit-testing the surrounding code easier. Thus, mock openAndReadFile to unit-test the surrounding code, and test openAndReadFile using integration-testing.

    评论
    解决 无用
    打赏 举报
  • dow72046 2019-06-01 11:08

    I'd strongly suggest using an interface instead of the filename string like the other answers here are recommending, but if you really must do this the only way is likely with a temp file. The decision to use a string file name has locked the code into assuming something to be present on the file system and has pushed in the responsibility of file management.

    评论
    解决 无用
    打赏 举报