简体   繁体   English

如何使用结构/接口模拟依赖关系进行测试

[英]How to use a struct/interface to mock dependency for testing

I'm new to go here... my objective is to unit test that a status is being updated in my ready(). 我是新来这里...我的目标是对我的ready()中正在更新的状态进行单元测试。 I've been looking at https://engineering.aircto.com/writing-testable-code-in-golang/ and trying to figure out how to adapt what they're doing to my use case, filling in gaps of golang knowledge where I can. 我一直在查看https://engineering.aircto.com/writing-testable-code-in-golang/并试图弄清楚如何使他们的工作适应我的用例,填补了golang知识的空白我可以的。

I'm getting the error cannot use fakeSession (type *FakeSession) as type *discordgo.Session in argument to ready but I'm not sure why I'm getting this error. 我收到错误消息,无法在参数ready中将fakeSession(类型* FakeSession)用作类型* discordgo.Session,但我不确定为什么会收到此错误。

main.go main.go

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"

    "github.com/bwmarrin/discordgo"
)

var (
    // bot token used for this bot when connecting
    token    = os.Getenv("DISCORD_BOT_TOKEN")
    status   = os.Getenv("BOT_STATUS")
)

func main() {
    // initiate Discord bot

    // Register ready as a callback for the ready events.
    discordConnection.AddHandler(ready)

    // running the app, waiting to receive a close signal
}

// This function will be called (due to AddHandler above) when the bot receives
// the "ready" event from Discord.
func ready(session *discordgo.Session, event *discordgo.Ready) {

    // Set the playing status.
    session.UpdateStatus(0, status)
}

main_test.go main_test.go

type FakeSession struct {
    status  string
    idle    int
}

func (f *FakeSession) UpdateStatus(idle int, game string) error {
    f.idle, f.status = idle, game
    return nil
}

func TestStatusIsUpdated(t *testing.T) {
    readyDependency := &discordgo.Ready{}
    fakeSession := &FakeSession{}

    ready(fakeSession, readyDependency)

    // @todo assert that idle/game status were set to correct values
}

As @Andrew pointed out discordgo.Session is a go struct (from the docs link you posted type Session struct { ) 正如@Andrew指出discordgo.Session是一个go结构(从您发布的docs链接type Session struct {

structs are Concrete types in go and are unable to be substituted. structs是go中的具体类型,无法替换。 The only argument go compiler will allow for ready is a pointer to a session. 编译器允许ready的唯一参数是指向会话的指针。

To break this dependency you can create a custom interface owned and controlled by your project using the methods that you need. 要打破这种依赖性,您可以使用所需的方法创建由项目拥有和控制的自定义接口 This will allow you to create and call ready with a fake structure for your tests. 这将使您ready使用伪造的结构来创建和调用ready的测试。

Sometimes 3rd party libraries already have interfaces so it's usually worth-while to scan their godoc to see which interfaces are available before creating your own. 有时第三方库已经具有接口,因此通常值得在创建自己的godoc之前先扫描其godoc以查看哪些接口可用。


But if you have to create your own for testing (and I find myself regularly having to do this), it might look like: 但是,如果您必须创建自己的测试文件(我发现自己经常必须这样做),则可能看起来像:

type StatusUpdater interface {
   UpdateStatus(int, string)
}

// This function will be called (due to AddHandler above) when the bot receives
// the "ready" event from Discord.
func ready(s StatusUpdater, event *discordgo.Ready) {

    // Set the playing status.
    s.UpdateStatus(0, status)
}

Now the dependency on discordgo.Session has been broken, and your test code can call ready function with its fake session, and then make assertions on it! 现在,对discordgo.Session的依赖已被破坏,您的测试代码可以使用其伪造的会话调用ready函数,然后对其进行断言!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM