草庐IT

mongodb - 在 Go 中模拟 MongoDB 响应

coder 2024-07-08 原文

我正在从 MongoDB 获取文档并将其传递给函数 transform,例如

var doc map[string]interface{}
err := collection.FindOne(context.TODO(), filter).Decode(&doc) 
result := transform(doc)

我想为 transform 编写单元测试,但我不确定如何模拟来自 MongoDB 的响应。理想情况下,我想设置这样的东西:

func TestTransform(t *testing.T) {
    byt := []byte(`
    {"hello": "world",
     "message": "apple"}
 `)

    var doc map[string]interface{}

    >>> Some method here to Decode byt into doc like the code above <<<

    out := transform(doc)
    expected := ...
    if diff := deep.Equal(expected, out); diff != nil {
        t.Error(diff)
    }
}

一种方法是将 json.Unmarshal 转换为 doc,但这有时会产生不同的结果。例如,如果 MongoDB 中的文档中有一个数组,那么该数组将被解码为 doc 作为 bson.A 类型而不是 []interface{} 类型。

最佳答案

我团队的一名成员最近发现在 GO 的官方 MongoDB 驱动程序中有一个隐藏的 gem :https://pkg.go.dev/go.mongodb.org/mongo-driver@v1.9.1/mongo/integration/mtest .尽管该包处于实验模式并且不保证向后兼容性,但它可以帮助您执行单元测试,至少对于这个版本的驱动程序是这样。

您可以查看这篇很酷的文章,其中包含大量有关如何使用它的示例:https://medium.com/@victor.neuret/mocking-the-official-mongo-golang-driver-5aad5b226a78 .此外,这里是包含本文代码示例的存储库:https://github.com/victorneuret/mongo-go-driver-mock .

因此,根据您的示例和文章中的示例,我认为您可以尝试如下操作(当然,您可能需要对此进行调整和试验):

func TestTransform(t *testing.T) {
    mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
    defer mt.Close()

    mt.Run("find & transform", func(mt *mtest.T) {
        myollection = mt.Coll
        expected := myStructure{...}

        mt.AddMockResponses(mtest.CreateCursorResponse(1, "foo.bar", mtest.FirstBatch, bson.D{
            {"_id", expected.ID},
            {"field-1", expected.Field1},
            {"field-2", expected.Field2},
        }))

        response, err := myFindFunction(expected.ID)
        if err != nil {
            t.Error(err)
        }

        out := transform(response)
        if diff := deep.Equal(expected, out); diff != nil {
            t.Error(diff)
        }
    })
}

或者,您可以通过与 Docker 容器的集成测试以自动化方式执行更真实的测试。有一些很好的软件包可以帮助您解决这个问题:

我在 dockertest 库中遵循这种方法来自动化一个完整的集成测试环境,该环境可以通过 进行 setUptearDown go test -v -run Integration 命令。在此处查看完整示例:https://github.com/AnhellO/learn-dockertest/tree/master/mongo .

希望这对您有所帮助。

关于mongodb - 在 Go 中模拟 MongoDB 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56772452/

有关mongodb - 在 Go 中模拟 MongoDB 响应的更多相关文章

  1. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  2. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  3. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  4. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

  5. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

  6. ruby - 在 RSpec 中 stub /模拟全局常量 - 2

    我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho

  7. ruby-on-rails - rspec 模拟对象属性赋值 - 2

    我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat

  8. ruby - 如何使用 rspec stub /模拟对命令行的调用? - 2

    我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy

  9. ruby-on-rails - Textmate 'Go to symbol' 相当于 Vim - 2

    在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol

  10. ruby - 接收 block 作为参数的模拟方法 - 2

    我有一个或多或少这样的场景classAdefinitialize(&block)b=B.new(&block)endend我正在对A类进行单元测试,我想知道B#new是否正在接收传递给A#new的block。我使用Mocha作为模拟框架。这可能吗? 最佳答案 我用Mocha和RSpec都试过了,虽然我可以通过测试,但行为不正确。从我的实验中,我得出结论,验证block是否已通过是不可能的。问题:为什么要传递一个block作为参数?block将用于什么目的?什么时候调用?也许这确实是您应该用类似的东西测试的行为:classBlockP

随机推荐