Reflection 如何使用反射实现或模拟Go接口?

Reflection 如何使用反射实现或模拟Go接口?,reflection,mocking,go,stub,stubbing,Reflection,Mocking,Go,Stub,Stubbing,我想用反射实现Go接口,以生成mock和stub。但是如果我看了这个包,我就不知道怎么做了(也许这是不可能的) 示例:测试func是否在以下位置调用WriteHeader(404): 使用RhinoMocks(C#)我会这样写: var responseWriterMock = MockRepository.GenerateMock<ResponseWriter>(); funcToTest(responseWriterMock); responseWriterMock.Asse

我想用反射实现Go接口,以生成mock和stub。但是如果我看了这个包,我就不知道怎么做了(也许这是不可能的)

示例:测试func是否在以下位置调用
WriteHeader(404)

使用RhinoMocks(C#)我会这样写:

var responseWriterMock = MockRepository.GenerateMock<ResponseWriter>();

funcToTest(responseWriterMock);

responseWriterMock.AssertWasCalled(rw => rw.WriteHeader(404));
var responseWriterMock=MockRepository.GenerateMock();
funcToTest(responseWriterMock);
调用responseWriterMock.Assertwas(rw=>rw.WriteHeader(404));
如何使用反射实现Go接口

附录


据我所知以及的答案,不可能在运行时创建新类型


您可能想尝试一下,它应该支持在其范围内定义新类型。

不幸的是,由于该语言的静态特性,反射包有点有限,无法在运行时创建动态对象。这可能永远不可能

我可以提出一些解决方案——都涉及在设计时创建任何存根/模拟

  • 手动编写模拟

    我见过人们沿着这条路走下去,一旦代码库变大,它很快就会变得难以忍受

    一般来说,我们的想法是编写一个实现接口的结构。在每个方法中,您添加的代码会增加一些计数器(以便跟踪调用),并且通常会返回硬编码的值或作为结构配置提供的值

  • 使用工具箱

    在撰写本文时,这似乎是提供模拟支持的最受欢迎的项目。然而,由于该项目提供了其他特性,有多少类似的特性是由于模拟功能本身造成的,这是值得怀疑的

    我没有使用过这个工具包,也不能提供详细的分析,看它是否有用

    看看自述文件,它似乎采取了一种非常类似于手动模拟的方法(如上所述)。它在顶部提供了一些帮助程序代码,但伪方法仍然需要手动键入。然后通过字符串指定方法来完成测试中的存根,这违背了Go语言的静态特性,对某些用户来说可能是个问题

  • 使用Go的官方工具

    自从我上次写这篇文章以来,这个工具似乎越来越受欢迎。此外,作为官方的Go项目,可以预期该工具将很快采用任何新的Go特性。它对go模块的支持就是一个很好的例子,其他工具都落后了

    它确实采取了一种特定的方法来嘲弄。您需要在测试代码的开头指定您的测试期望。在测试结束时,框架检查是否满足了所有期望。意外调用会导致框架测试失败

    如果您使用的是像这样的定制测试框架,那么干净地集成可能会很棘手。在我的项目中,我编写了帮助函数来弥补这个差距

    虽然它确实为您生成假方法,但它生成的断言和期望方法采用
    interface{}
    类型。这允许框架提供更高级的参数匹配器,但也意味着您需要确保以正确的顺序传递正确数量的参数

    根据我的经验,使用此工具编写的测试往往会有更大的侧面,有时阅读起来更复杂。从好的方面来说,它们通常会更彻底地测试事物,并且更具表现力

  • 使用该工具

    该工具在Cloud Foundry生态系统中得到了大量使用,并已被证明是一种可行的选择

    它允许您跟踪给定方法被调用的次数、用于调用该方法的参数,并使用自定义实现伪造整个方法或指定要返回的结果值

    它之所以成为一个好的选择,是因为它产生了非常明显的假货。开发人员不需要使用字符串名称来指定方法,也不需要记住参数的顺序和数量。生成的helper方法与原始方法非常相似,具有正确类型和顺序的参数


  • 我上面提供的一些选项要求您运行命令行工具来生成模拟的源代码。随着需要模拟的接口数量的快速增长,有一个很酷的技巧可以用来跟踪所有内容

    您可以利用go中的
    go:generate
    功能轻松生成所有存根/赝品,而无需调用任何命令参数或手动运行每个界面的工具

    您只需在包含界面的文件中添加适当的
    go:generate
    注释

    mock

    //go:generate mockgen -source person.go
    
    type Person interface {
      Name() string
      Age() int
    }
    
    造假者

    //go:generate counterfeiter ./ Person
    
    type Person interface {
      Name() string
      Age() int
    }
    

    然后,您可以在项目的根目录中运行
    go generate./…
    命令,所有存根/伪存根都将为您重新生成。如果您正在与多个合作者合作的项目中工作,这可能是一个救命稻草。

    请添加一些可能是无效的Go代码,以显示您希望实现的目标。一、 首先,对你的要求有一点了解。是的,我想你不需要反思;-)我添加了一个示例,正如您所见,我只需要实现模拟和创建结构的函数。
    go:generate
    技巧非常有用。谢谢
    //go:generate counterfeiter ./ Person
    
    type Person interface {
      Name() string
      Age() int
    }