Compartilhamento de tecnologia

Faça testes unitários

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Na linguagem Go, o teste unitário é implementado por meio do pacote de testes na biblioteca padrão, que fornece um conjunto de funções que tornam a escrita, a execução e o gerenciamento de testes unitários simples e eficientes.

1. Regras

  • Testar regras de nomenclatura de arquivos
    A regra de nomenclatura de arquivo de teste em Go é adicionar_test.go .Por exemplo, se você tiver umcalculator.go arquivo, o arquivo de teste correspondente deve sercalculator_test.go

  • Regras de nomenclatura para funções de teste
    A função de teste deve começar comTest começa e pode ser seguido por qualquer string não vazia, por exemploTestAddTestSubtract espere.

  • usar testing.T Faça afirmações e relatórios de erros
    Na função de teste, usetesting.T Digite parâmetros para gerenciar o status e a saída do teste.você pode usart.Error*t.Fail* e outros métodos para indicar falha no teste e gerar informações de erro relevantes.

2. Exemplo de teste unitário

2.1 Caso de teste único

Uma função de calculadora é definida no pacote da calculadora e a implementação específica é a seguinte:

package calculator

func Add(a, b int) int {
	return a + b
}
  • 1
  • 2
  • 3
  • 4
  • 5

No diretório atual, criamos um arquivo de teste calculator_test.go e definimos uma função de teste da seguinte forma:

package calculator

import "testing"


func TestAdd(t *testing.T) {
	result := Add(1, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Para executar este teste de unidade, use o comando go test.Na linha de comando, insira o diretório que contém calculator.go e calculator_test.go e executego test, esses resultados são os seguintes

go test
PASS
ok      modu    0.226s
  • 1
  • 2
  • 3

2.2 Vários casos de teste

Adicione a seguinte função de teste em calculator_test.go:

func TestAdd2(t *testing.T) {
	result := Add(3, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Para ver melhor a execução de cada caso de teste nos resultados de saída, podemosgo test -vparâmetros para permitir a saída de resultados de teste completos.

go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
    calculator_test.go:17: Add(1,2) return 5, expected 3
--- FAIL: TestAdd2 (0.00s)
FAIL
exit status 1
FAIL    modu    0.216s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.3 Especifique casos de teste em execução

go test -run O comando pode executar testes de acordo com o modo especificado. Este comando oferece suporte a expressões regulares para selecionar funções de teste a serem executadas.

Por exemplo, após corrigir o caso de uso TestAdd2, passego tes -run=Add2Execute apenas o caso de teste TestAdd2, o resultado é

go test -run=Add2 -v
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
PASS
ok      modu    0.198s
  • 1
  • 2
  • 3
  • 4
  • 5

4. Pule alguns casos de teste
Adicionar nova função de teste

func TestAdd3(t *testing.T) {
	if testing.Short() {
        t.Skip("short模式下会跳过该测试用例")
    }
	
	result := Add(3, 2)
	expected := 5
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

ao executargo test -shorQuando t, será ignoradotesting.Short()O caso de teste marcado, o resultado é

go test -short -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN   TestAdd3
    calculator_test.go:23: short模式下会跳过该测试用例
--- SKIP: TestAdd3 (0.00s)
PASS
ok      modu    0.635s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. Grupos de teste e subtestes

3.1 Grupos de teste e subtestes

Através de grupos de testes e subtestes, você pode adicionar mais casos de testes e visualizar os resultados de uma forma mais amigável

func TestAdd(t *testing.T) {
	tests := []struct {
		name     string
		x, y     int
		expected int
	}{
		{"Add1", 1, 2, 3},
		{"Add2", 3, 3, 6},
		{"Add3", 4, 5, 8},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

corrergo test -v,vire para fora

go test -v
=== RUN   TestAdd
=== RUN   TestAdd/Add2
=== RUN   TestAdd/Add3
    calculator_test.go:51: Add(4, 5) returned 9, expected 8
--- FAIL: TestAdd (0.00s)
    --- PASS: TestAdd/Add1 (0.00s)
    --- PASS: TestAdd/Add2 (0.00s)
    --- FAIL: TestAdd/Add3 (0.00s)
FAIL
exit status 1
FAIL    modu    0.190s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.2 Testes paralelos

A linguagem Go oferece suporte inerente à simultaneidade, portanto, ao adicionart.Parallel()Para conseguir paralelização de testes de driver.

func TestAdd(t *testing.T) {
	t.Parallel()  // 将 TLog 标记为能够与其他测试并行运行
	// 这里使用匿名结构体定义了若干个测试用例
	// 并且为每个测试用例设置了一个名称
	tests := []struct {
		name     string
		x, y     int
		expected int
	}{
		{"Add1", 1, 2, 3},
		{"Add2", 3, 3, 6},
		{"Add3", 4, 5, 8},
	}

	for _, tc := range tests {
		tc := tc  // 注意这里重新声明tt变量(避免多个goroutine中使用了相同的变量)
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()  // 将每个测试用例标记为能够彼此并行运行
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

3.3 Cobertura do teste

usargo test -coverpara visualizar a cobertura do teste

go test -cover
PASS
        modu    coverage: 100.0% of statements
ok      modu    1.149s
  • 1
  • 2
  • 3
  • 4

4. Kit de ferramentas de teste de unidade Go – testemunhe

Ao realizar testes unitários na linguagem Go, como a função de asserção oficial não está integrada, geralmente precisamos usar um grande número deif...else... declaração para verificar os resultados do teste.No entanto, usando bibliotecas de terceiros, comotestify/assert, podemos chamar facilmente uma variedade de funções de asserção comumente usadas, que não apenas simplificam o código de teste, mas também geram informações de descrição de erro claras e fáceis de entender, ajudando-nos a localizar rapidamente o problema.

No exemplo acima, usamosif...else...Declaração para verificar os resultados do teste

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Disponível agoratestify/assertO processo de julgamento acima é simplificado da seguinte forma:

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			assert.Equal(t, result, tc.expected)
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

testify/requiretertestify/assertTodas as funções de asserção, a única diferença entre elas é quetestify/requireSe um caso de teste com falha for encontrado, o teste será encerrado imediatamente.