如何在golang中为包含通道、filewalk和api调用的程序编写单元测试?

Posted

技术标签:

【中文标题】如何在golang中为包含通道、filewalk和api调用的程序编写单元测试?【英文标题】:How to write unit test for a program that contains channels, filewalk and api call in golang? 【发布时间】:2022-01-10 23:56:46 【问题描述】:

我的程序整体如下。

func main() 

    flag.Parse()

    if *token == "" 
        log.Fatal(Red + "please provide a client token => -token=$token")
    

    tokenSource := oauth2.StaticTokenSource(&oauth2.TokenAccessToken: *token)
    oauthClient := oauth2.NewClient(context.TODO(), tokenSource)
    client := putio.NewClient(oauthClient)

    //paths := make(chan string)
    var wg = new(sync.WaitGroup)
    for i := 0; i < 50; i++ 
        wg.Add(1)
        go worker(paths, wg, client)
    
    WalkFilePath()
    //if err := filepath.Walk(*rootpath, func(path string, info os.FileInfo, err error) error 
    //  if err != nil 
    //      return fmt.Errorf("Failed to walk directory: %T %w", err, err)
    //  
    //  if !info.IsDir() 
    //      paths <- path
    //  
    //  return nil
    //); err != nil 
    //  panic(fmt.Errorf("failed Walk: %w", err))
    //
    close(paths)
    wg.Wait()


// walks the file path and sends paths to channel
func WalkFilePath() 
    if err := filepath.Walk(*rootpath, func(path string, info os.FileInfo, err error) error 
        if err != nil 
            return fmt.Errorf("Failed to walk directory: %T %w", err, err)
        
        if !info.IsDir() 
            paths <- path
        
        return nil
    ); err != nil 
        panic(fmt.Errorf("failed Walk: %w", err))
    


func worker(paths <-chan string, wg *sync.WaitGroup, client *putio.Client) 
    defer wg.Done()
    for path := range paths 
        f, err := os.Open(path)
        if err != nil 
            log.Printf(Red + "Failed to open file %v for reading" + Reset, f.Name())
        
        upload, err := client.Files.Upload(context.TODO(), f, path, 0)
        if err != nil 
            log.Printf(Red + "Failed to upload file %v" + Reset, upload.File.Name)
        
        log.Printf(Green+ "File %v has been uploaded succesfully" + Reset, upload.File.Name)
    

我确实编写了代码。这是我能做的最干净的事情,我被告知要为程序编写一个单元测试。我糊涂了。例如,考虑WalkFilePath 函数。我应该提供什么以及我应该期望什么样的结果来测试该功能。因为它包含channel通信含义goroutines。有没有办法清楚地为这个程序编写单元测试?或者我应该更改在这种情况下对我不利的代码结构。顺便说一句,程序运行正常。

【问题讨论】:

"顺便说一句,程序运行正常。"那个程序没有。你在WalkFilePath中引用了未定义的变量。 我没有放不必要的代码。这就是为什么。 【参考方案1】:

像大多数事情一样,Go 对于如何测试非常固执己见。请务必阅读https://go.dev/doc/tutorial/add-a-test

例如,考虑 WalkFilePath 函数。我应该提供什么以及我应该期望什么样的结果来测试该功能。

WalkFilePath 的输入应该pathsrootpath。您的WalkFilePath 不会从任何地方获得pathsrootpath,因此此代码不会按原样编译(当然,测试将有助于捕获这些内容)。

WalkFilePath 的测试可能会像这样进行:

    testdata/下的项目中创建一个文件系统结构,一个目录expressly set aside for data used for testing。创建子目录和文件。对于一个可能看起来像这样的示例:

    testdata/
       walktest/
          dir1/
             file1.txt
          dir2/
              file2.txt
              dir3/
                 file3.txt
    

    现在您可以定义您将从频道中获得的预期数据。

    expected_paths := []string
       "testdata/walktest/dir1/file1.txt",
       "testdata/walktest/dir2/file2.txt",
       "testdata/walktest/dir3/file3.txt"
    
    

    现在您需要更改 WalkFilePath 以获取 rootpathpaths 的参数。

    func WalkFilePath(rootdir string, paths chan<- string) 
    

    现在您可以编写测试了。

    func TestWalkFilePath(t *testing.T(
       paths := make(chan string)
       go WalkFilePath("testdata/walktest")
       results := make([]string,0)
       for path := range paths 
         results = append(results, path)
       
       exp, res := strings.Join(expected_paths, ""), strings.Join(results, "")
       if exp != res 
         t.Errorf("Expected %s got %s", exp, res)
       
    
    

因为它包含通道通信意义的goroutines。

在单元测试中使用通道和 goroutine 是完全正常和有效的。

【讨论】:

以上是关于如何在golang中为包含通道、filewalk和api调用的程序编写单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VSTS 中为 Xamarin iOS 和 Android 部署添加快速通道工具

在 Golang 中同时读取多个通道

如何在 Keras 中为维度 (2505,10) 的数据设计 CNN?

如何使用 PySide 在 Maya 中为通道框添加新按钮?

如何在 Spring Integration DSL 中为通道设置多个消息处理程序?

Golang 缓冲通道在发送之前接收数据