12

问题

我想知道t.CleanupGo1.14中引入的用例。与使用 defer 相比,t.Cleanup 有什么便利?

https://golang.org/pkg/testing/#T.Cleanup

  • 样本

例如,假设我们创建了一个临时目录,当我们测试它时,我们想删除我们创建的临时目录。

t.Cleanup可用于编写测试,如下所示,但它也可以用作defer os.RemoveAll(tempDir).

package mypkg

import (
    "io/ioutil"
    "os"
    "testing"
)

func TestDirwalk(t *testing.T) {
    tempDir, err := ioutil.TempDir(".", "temp")
    if err != nil {
        t.Errorf("create tempDir: %v", err)
    }
    t.Cleanup(func() { os.RemoveAll(tempDir) })

    // something...
}
4

3 回答 3

22

如果您的测试出现恐慌,也会调用清理函数,因此在您的情况下两者都可以工作。

T.Cleanup()如果您的测试调用其他函数并传递,则使用的优势变得明显testing.T。显然 using deferin 这些函数将在这些函数返回之前执行,但是如果您使用 注册清理函数T.Cleanup(),那么它们将仅在测试结束时被调用。

T.Cleanup()其视为defer. 它还记录了传递的函数用于清理目的。

于 2020-05-05T09:14:14.760 回答
13

t.Cleanup当测试不关心资源本身时,对于清理由帮助函数分配的资源很有用。

例子

考虑测试服务层。该服务使用 a*sql.DB但不自己创建它。

package testutils

import (
  "testing"

  "my/db"
  "my/domain"
)

func NewTestSubject(t *testing.T) *domain.Service {
  t.Helper()  
  sqldb := newDatabase(t)
  s, _ := domain.NewService(sqldb)
  return s
}

func newDatabase(t *testing.T) *sql.DB {
  t.Helper()
  d, _ := db.Create()
  t.Cleanup(func() {
    d.Close()
  })
}

没有t.Cleanup newTestSubject将不得不返回(*domain.Service, *sql.DB),泄漏有关domain.Service的建设细节。

于 2020-05-05T09:08:13.390 回答
3

除了其他人指出的之外,t.Cleanup()在处理并行子测试时也很有用,其中清理应该只在所有子测试完成后运行。考虑

func TestSomething(t *testing.T){
   setup()
   defer cleanup()
   t.Run("parallel subtest 1", func(t *testing.T){
      t.Parallel()
      (...)
   })
   t.Run("parallel subtest 2", func(t *testing.T){
      t.Parallel()
      (...)
   })
}

这不起作用,因为测试函数将在子测试仍在运行时返回,导致子测试所需的资源被defer cleanup().

t.Cleanup()解决此问题的方法是将子测试包装在另一个测试中

func TestSomething(t *testing.T){
   setup()
   defer cleanup()
   t.Run("parallel tests", func(t *testing.T){
      t.Run("subtest 1", func(t *testing.T){
         t.Parallel()
         (...)
      })
      t.Run("subtest 2", func(t *testing.T){
         t.Parallel()
         (...)
      })
   })
}

看起来不错,但随着t.Cleanup()它变得更好

func TestSomething(t *testing.T){
   setup()
   t.Cleanup(cleanup)
   t.Run("parallel subtest 1", func(t *testing.T){
      t.Parallel()
      (...)
   })
   t.Run("parallel subtest 2", func(t *testing.T){
      t.Parallel()
      (...)
   })
}
于 2020-10-02T21:20:11.757 回答