Golang中如何编写返回类型的测试

Golang中如何编写返回类型的测试 我一直在学习这门课程通过测试学习Go。我喜欢TDD的概念,但在编写自己的测试时遇到了困难。

我正在编写一个程序,该程序将从’.sql’文件加载查询,然后运行它并将结果存储为报告。

我不太确定该如何测试这个功能,我有一个如下所示的可运行函数,但测试无法通过…

函数

// LoadQuery retrieves .sql file from filesystem
func LoadQuery() {
	// Load Query from file
	content, err := ioutil.ReadFile("query.sql")
	if err != nil {
		log.Fatal("File not found")
	}
	// Convert Query to String
	query := string(content[:])
	return query
}

我的测试

func TestLoadQuery(t *testing.T) {

	t.Run("load sql from file", func(t *testing.T) {

		if LoadQuery() != string {
			t.Error("Expected string")
		}
	})
}

更多关于Golang中如何编写返回类型的测试的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

这段代码能编译通过吗?LoadQuery()函数返回的是字符串,但没有指定返回参数——这应该在编译时出现"too many arguments to return"错误而失败。

另外,如果你确实将LoadQuery()改为返回字符串,这个测试就多余了。但即使你想测试某个变量是否为特定类型(比如LoadQuery返回interface{}),也不应该用x != string这样的方式来测试。简单示例:https://play.golang.org/p/aGvCH8OkrWW

更多关于Golang中如何编写返回类型的测试的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果你指定了返回类型为 string,然后测试返回的变量是 string 类型,那么这种特定的测试就是多余的——编译器会保证在这种情况下返回类型始终string。除非你在该函数中返回一个字符串,否则应用程序将无法编译,因此这个测试实际上并没有测试任何内容。在你的 SQL 查询示例中,一个更有用的测试可能是结果不是字符串(例如,如果你总是期望返回一个 SQL 查询),或者返回的 SQL 查询字符串始终是符合你目的的有效查询(我想这类似于你刚刚发布的第二个示例)。希望这说得通,如果还有不清楚的地方,请告诉我,我可以尝试用另一种方式解释。图片

是的,在我添加了返回类型为string之后,这段代码才能编译通过。

你能详细说明为什么这个测试会是多余的吗?难道测试不是始终必要的吗?

要为这个需求编写测试,即从文件中读取SQL语句并转换成字符串发送给数据库查询客户端……我遇到的问题是我生成报告的查询语句本身就有数千行。这是个问题,因为到目前为止我看到的测试都是用反引号来编写成功测试用例的,比如 select * from table

话虽如此,也许我可以使用模式匹配表达式,这样测试用例就可以写成:

got := LoadQuery()
want := `%select%from%`

if got != want {
t.Error("file not sql")
}

感谢你的回复,非常感激任何能增进我对Go测试理解的进一步意见!😊

添加我的最终解决方案。欢迎进一步反馈,但我的问题已经得到解答,对此我很满意。

首先是我的代码:

package main
import (
	"fmt"
	"io/ioutil"
	"log"

)

var err error

func main() {
	fmt.Println(LoadQuery())
}

// LoadQuery retrieves .sql file from filesystem
func LoadQuery() string {
	// Load Query from file
	content, err := ioutil.ReadFile("code_checker.sql")
	if err != nil {
		log.Fatal("File not found")
	}
	// Convert Query to String
	query := string(content[:])
	return query
}

当我移除字节转字符串行并运行测试时,出现以下错误:

c:\dev\go\src\###\reporter.go:53:2: cannot use content (type []byte) as type string in return argument
FAIL	### [build failed]
Error: Tests failed.

使用字符串转换后的情况:

2018/08/21 14:15:46 File not found
FAIL		0.200s
Error: Tests failed.

以及我的测试:

package main

import (
	"fmt"
	"testing"
)

func TestLoadQuery(t *testing.T) {

	t.Run("load sql from file", func(t *testing.T) {
		// Test fails if either no file present or not string returned.
		if len(LoadQuery()) > 0 {
			fmt.Println("Empty String")
		}
	})
}

我认为这个测试可以改进的方式包括…理解如何为测试模拟文件。将测试文本更改为更符合惯例,也许这个测试的名称应该是"从文件加载字符串",因为这才是我们实际在做的事情。

您的测试无法通过是因为函数 LoadQuery 的返回类型声明不正确,并且测试中的断言方式有误。以下是具体问题和解决方案:

问题分析

  1. 函数返回类型不匹配LoadQuery 函数在声明时没有指定返回类型,但实际代码中尝试返回 query(字符串类型)。这会导致编译错误。
  2. 测试断言错误:在测试中,LoadQuery() != string 试图将函数返回值与类型 string 比较,这是无效的语法。应检查返回值是否为预期的字符串内容。

修正后的代码

函数修正

LoadQuery 函数修改为返回字符串类型,并处理错误而不是直接调用 log.Fatal(在测试中直接退出会中断测试流程)。返回错误可以让测试更灵活地验证不同情况。

// LoadQuery retrieves .sql file from filesystem and returns the query as a string.
func LoadQuery() (string, error) {
    content, err := ioutil.ReadFile("query.sql")
    if err != nil {
        return "", err // 返回错误而不是终止程序
    }
    return string(content), nil
}

测试修正

测试应验证函数返回的字符串内容是否符合预期,并检查错误处理。使用 t.Helper() 标记辅助函数以在错误报告中提供更清晰的上下文。

func TestLoadQuery(t *testing.T) {
    t.Run("load sql from file", func(t *testing.T) {
        got, err := LoadQuery()
        if err != nil {
            t.Fatalf("Expected no error, but got: %v", err)
        }
        
        // 示例:验证返回的字符串非空且包含特定SQL关键字(根据实际文件内容调整)
        if got == "" {
            t.Error("Expected non-empty query string")
        }
        // 可选:检查具体内容,例如是否包含 "SELECT"
        if !strings.Contains(got, "SELECT") {
            t.Error("Expected query to contain 'SELECT'")
        }
    })
    
    // 可选:测试文件不存在的情况
    t.Run("file not found", func(t *testing.T) {
        // 临时重命名或移除 "query.sql" 文件以模拟缺失情况
        // 注意:在实际项目中,使用依赖注入或模拟文件系统会更可靠
        originalName := "query.sql"
        tempName := "query_temp.sql"
        os.Rename(originalName, tempName)
        defer os.Rename(tempName, originalName) // 测试后恢复文件
        
        _, err := LoadQuery()
        if err == nil {
            t.Error("Expected error when file is missing")
        }
    })
}

关键点说明

  • 返回类型和错误处理:函数应明确返回 (string, error),允许测试验证正常和错误情况。
  • 测试内容匹配:通过检查返回字符串的实际内容(如非空或包含特定关键字)来确保功能正确。
  • 文件操作测试:对于文件缺失的情况,通过临时修改文件系统状态来测试错误路径,但更健壮的方法是使用接口抽象文件操作(如 io.Reader),以便在测试中注入模拟依赖。

通过以上修正,您的测试将能够编译并通过,同时覆盖正常和异常场景。

回到顶部