如何使用Go中的测试包进行测试设置

时间:2014-05-19 04:36:41

标签: unit-testing go

如何使用testing package进行整体测试设置处理,为所有测试设置阶段?

作为Nunit的一个例子,有一个[SetUp]属性。

[TestFixture]
public class SuccessTests
{
  [SetUp] public void Init()
  { /* Load test data */ }
}

8 个答案:

答案 0 :(得分:102)

从Go 1.4开始,您可以实现设置/拆卸(无需在每次测试之前/之后复制您的功能)。文档在主要部分中列出了here

  

TestMain在主goroutine中运行,可以进行任何设置和   在打电话给m.Run时需要拆机。然后应该打电话   os.Exit与m.Run的结果

我花了一些时间才弄清楚这意味着如果测试包含函数func TestMain(m *testing.M),那么将调用此函数而不是运行测试。在这个函数中,我可以定义测试的运行方式。例如,我可以实现全局设置和拆解:

func TestMain(m *testing.M) {
    setup()
    code := m.Run() 
    shutdown()
    os.Exit(code)
}

其他一些例子can be found here

  

TestMain功能最新添加到Go的测试框架中   release是几个测试用例的简单解决方案。 TestMain   提供了一个全局钩子来执行设置和关闭,控制   测试环境,在子进程中运行不同的代码或检查   对于测试代码泄露的资源。大多数包都不需要   TestMain,但对于那些时代它是一个受欢迎的补充   需要的。

答案 1 :(得分:32)

这可以通过在init()文件中放置_test.go函数来实现。这将在init()函数之前运行。

// package_test.go
package main

func init() {
     /* load test data */
}

_test.init()将在包init()函数之前调用。

答案 2 :(得分:18)

给出了单元测试的简单功能:

package math

func Sum(a, b int) int {
    return a + b
}

您可以使用返回拆卸功能的设置功能对其进行测试。在调用setup()之后,您可以对teardown()进行延期调用。

package math

import "testing"

func setupTestCase(t *testing.T) func(t *testing.T) {
    t.Log("setup test case")
    return func(t *testing.T) {
        t.Log("teardown test case")
    }
}

func setupSubTest(t *testing.T) func(t *testing.T) {
    t.Log("setup sub test")
    return func(t *testing.T) {
        t.Log("teardown sub test")
    }
}

func TestAddition(t *testing.T) {
    cases := []struct {
        name     string
        a        int
        b        int
        expected int
    }{
        {"add", 2, 2, 4},
        {"minus", 0, -2, -2},
        {"zero", 0, 0, 0},
    }

    teardownTestCase := setupTestCase(t)
    defer teardownTestCase(t)

    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            teardownSubTest := setupSubTest(t)
            defer teardownSubTest(t)

            result := Sum(tc.a, tc.b)
            if result != tc.expected {
                t.Fatalf("expected sum %v, but got %v", tc.expected, result)
            }
        })
    }
}

Go测试工具将在shell控制台中报告日志记录语句:

% go test -v
=== RUN   TestAddition
=== RUN   TestAddition/add
=== RUN   TestAddition/minus
=== RUN   TestAddition/zero
--- PASS: TestAddition (0.00s)
    math_test.go:6: setup test case
    --- PASS: TestAddition/add (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    --- PASS: TestAddition/minus (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    --- PASS: TestAddition/zero (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    math_test.go:8: teardown test case
PASS
ok      github.com/kare/go-unit-test-setup-teardown 0.010s
% 

您可以使用此方法将一些其他参数传递给setup / teardown。

答案 3 :(得分:11)

通常,go中的测试不会以与其他语言相同的方式编写。通常,测试功能相对较少,但每个测试功能都包含一组表驱动的测试用例。见this article written by one of the Go team.

使用表驱动测试,您只需在执行表中指定的各个测试用例的循环之前放置任何设置代码,然后再放入任何清理代码。

如果您仍然在测试功能之间拥有共享设置代码,则可以将共享设置代码提取到一个函数中,并使用sync.Once,如果它只执行一次非常重要(或者作为另一个答案建议,使用init(),但这样做的缺点是即使测试用例没有运行也会完成设置(可能是因为您使用{限制了测试用例) {1}}。)

我说如果你认为你需要在不同的测试之间进行共享设置,那么只要你真的需要它就应该进行思考,并且如果表格驱动的测试不会更好。

答案 4 :(得分:7)

Go测试框架没有任何等同于NUnit的SetUp attribute(标记在套件中的每个测试之前调用的函数)。但有几个选择:

  1. 只需在需要的每个测试中调用SetUp函数。

  2. 使用Go的测试框架的扩展来实现xUnit范例和概念。我想到了三个强大的选择:

  3. 这些库中的每一个都鼓励您将测试组织到与其他xUnit框架类似的套件/装置中,并在每个Test*方法之前调用套件/夹具类型的安装方法。

答案 5 :(得分:2)

如果有人正在寻找 @BeforeEach(在测试文件中的每个测试之前运行)和 @AfterEach(在测试文件中的每个测试之后运行)的替代方案,这里有一个帮助代码片段。

func CreateForEach(setUp func(), tearDown func()) func(func()) {
    return func(testFunc func()) {
        setUp()
        testFunc()
        tearDown()
    }
}

你可以在TestMain的帮助下像下面一样使用它

var RunTest = CreateForEach(setUp, tearDown)

func setUp() {
   // SETUP METHOD WHICH IS REQUIRED TO RUN FOR EACH TEST METHOD
   // your code here
}

func tearDown() {
  // TEAR DOWN METHOD WHICH IS REQUIRED TO RUN FOR EACH TEST METHOD
  // your code here
}

fun TestSample(t *testing.T) {
  RunTest(func() {
    // YOUR CODE HERE
  })
}

您也可以检查:go-beforeeach

答案 6 :(得分:0)

无耻的插件,我创建了https://github.com/houqp/gtest来帮助解决这个问题。

这是一个简单的例子:

import (
  "strings"
  "testing"
  "github.com/houqp/gtest"
)

type SampleTests struct{}

// Setup and Teardown are invoked per test group run
func (s *SampleTests) Setup(t *testing.T)      {}
func (s *SampleTests) Teardown(t *testing.T)   {}
// BeforeEach and AfterEach are invoked per test run
func (s *SampleTests) BeforeEach(t *testing.T) {}
func (s *SampleTests) AfterEach(t *testing.T)  {}

func (s *SampleTests) SubTestCompare(t *testing.T) {
  if 1 != 1 {
    t.FailNow()
  }
}

func (s *SampleTests) SubTestCheckPrefix(t *testing.T) {
  if !strings.HasPrefix("abc", "ab") {
    t.FailNow()
  }
}

func TestSampleTests(t *testing.T) {
  gtest.RunSubTests(t, &SampleTests{})
}

您可以使用不同的设置/拆卸例程集,在一个程序包中随心所欲地创建任何测试组。

答案 7 :(得分:0)

使用以下模板,您可以在每个测试方法中进行一行调用,同时进行设置和拆卸。

func setupTest() func() {
    // Setup code here

    // tear down later
    return func() {
        // tear-down code here
    }
}

func TestMethod(t *testing.T) {
    defer setup()()
    // asserts, ensures, requires... here
}