当前位置: 首页 > 面试题库 >

Go中的模拟功能

皇甫琛
2023-03-14
问题内容

我正在通过编写一个小型个人项目来学习Go。即使很小,我还是决定从头开始进行严格的单元测试,以学习Go的良好习惯。

琐碎的单元测试都很好而且花哨的,但是我现在对依赖项感到困惑;我希望能够用模拟函数替换一些函数调用。这是我的代码片段:

func get_page(url string) string {
    get_dl_slot(url)
    defer free_dl_slot(url)

    resp, err := http.Get(url)
    if err != nil { return "" }
    defer resp.Body.Close()

    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil { return "" }
    return string(contents)
}

func downloader() {
    dl_slots = make(chan bool, DL_SLOT_AMOUNT) // Init the download slot semaphore
    content := get_page(BASE_URL)
    links_regexp := regexp.MustCompile(LIST_LINK_REGEXP)
    matches := links_regexp.FindAllStringSubmatch(content, -1)
    for _, match := range matches{
        go serie_dl(match[1], match[2])
    }
}

我希望能够测试downloader()而不实际通过http获取页面-
即通过模拟get_page(更容易使用,因为它仅将页面内容作为字符串返回)或http.Get()。

我找到了这个线程:https :
//groups.google.com/forum/#!topic/golang- nuts/
6AN1E2CJOxI,这似乎与一个类似的问题有关。朱利安·菲利普斯(Julian
Phillips)提出了他的图书馆Withmock(http://github.com/qur/withmock)作为解决方案,但我无法使其正常工作。老实说,这是我的测试代码的相关部分,对我来说,这基本上是对货物的崇拜代码

import (
    "testing"
    "net/http" // mock
    "code.google.com/p/gomock"
)
...
func TestDownloader (t *testing.T) {
    ctrl := gomock.NewController()
    defer ctrl.Finish()
    http.MOCK().SetController(ctrl)
    http.EXPECT().Get(BASE_URL)
    downloader()
    // The rest to be written
}

测试输出如下:

ERROR: Failed to install '_et/http': exit status 1
output:
can't load package: package _et/http: found packages http (chunked.go) and main (main_mock.go) in /var/folders/z9/ql_yn5h550s6shtb9c5sggj40000gn/T/withmock570825607/path/src/_et/http

Withmock是否可以解决我的测试问题?我应该怎么做才能使其正常工作?


问题答案:

感谢您练习良好的测试!:)

就我个人而言,我不使用gomock(或任何模拟框架;没有它,Go中的模拟非常容易)。我要么将依赖项downloader()作为参数传递给函数,要么downloader()在类型上创建方法,并且该类型可以容纳该get_page依赖项:

type PageGetter func(url string) string

func downloader(pageGetterFunc PageGetter) {
    // ...
    content := pageGetterFunc(BASE_URL)
    // ...
}

主要:

func get_page(url string) string { /* ... */ }

func main() {
    downloader(get_page)
}

测试:

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader(t *testing.T) {
    downloader(mock_get_page)
}

方法2:制作download()一种类型的方法Downloader

如果您不想将依赖项作为参数传递,则还可以使get_page()一个类型成为成员,并使其download()成为该类型的方法,然后可以使用get_page

type PageGetter func(url string) string

type Downloader struct {
    get_page PageGetter
}

func NewDownloader(pg PageGetter) *Downloader {
    return &Downloader{get_page: pg}
}

func (d *Downloader) download() {
    //...
    content := d.get_page(BASE_URL)
    //...
}

主要:

func get_page(url string) string { /* ... */ }

func main() {
    d := NewDownloader(get_page)
    d.download()
}

测试:

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader() {
    d := NewDownloader(mock_get_page)
    d.download()
}


 类似资料:
  • 问题内容: 我正在尝试为向Web服务发出请求的程序包编写测试。我可能由于缺乏对TLS的了解而遇到问题。 目前,我的测试看起来像这样: 我的程序包具有一个要查询的Web服务基址的程序包变量(我希望它是一个常量。)。这是一个https URL。我在上面创建的测试服务器是纯HTTP,没有TLS。 默认情况下,我的测试失败,并显示错误“ tls:第一条记录看起来不像TLS握手”。 为了使它起作用,我的测试

  • 问题内容: 在Go中,TCP连接(net.Conn)是io.ReadWriteCloser。我想通过模拟TCP连接来测试我的网络代码。我有两个要求: 要读取的数据存储在字符串中 每当写入数据时,我都希望将其存储在某种缓冲区中,以便以后使用 是否有数据结构或简单的方法? 问题答案: 为什么不使用?它是一种并且具有获取存储数据的方法。如果需要将其设置为,则可以定义自己的类型: 并定义一个方法:

  • 问题内容: 如何在MySQL中的此表上做滞后处理以打印引号中的差异,例如: 问题答案: 这是我最喜欢的MySQL hack。 这是模拟滞后函数的方式: 保存上一行报价的值。对于第一行,@ quot是-1。 保留当前行的报价的值。 笔记: 子句在这里很重要,就像在常规窗口函数中一样。 您可能还想使用lag 来确保计算相同引号的差异。 您也可以以相同的方式实现行计数器 与该方案相比,与使用聚合函数,存

  • 问题内容: 有没有一种简单的方法可以在进行测试时模拟Hashicorp保险库? 我在Go中创建了一个可访问保险柜的服务,并希望为其创建适当的测试。 我没有找到我喜欢的简单解决方案(例如python中的moto)。我还尝试在docker中以dev模式使用Vault(采用系统测试路线),但我无法通过API写入文件。想法? 问题答案: 有没有一种简单的方法可以在Go测试中模拟HashiCorp Vaul

  • 问题内容: 情况: 我想从控制台获取密码输入- 而不回显用户键入的内容 。有什么可以和Go中的功能媲美吗? 我试过的 我尝试使用,但它回显了键入的内容。 问题答案: 您可以通过执行以下操作来关闭回显,然后在读取密码后将其重新打开

  • 问题内容: 我试过了 但这会引发语法错误。我也尝试过像这样修补 有什么办法吗? 问题答案: 是python 2.x中的关键字,将其用作属性会引发SyntaxError。您可以通过在文件开头使用来避免这种情况。 注意:您不能简单地使用,因为除非禁用该语句,否则不会调用您修改的print函数。 编辑:您还需要在每个要使用修改后功能的文件中使用它,否则它将被该语句掩盖。