监视Golang中的方法

Is there any way to spy on methods in Golang?

For example, suppose I have

type Object struct { 
    A int
    B string
    C *interface{}
}   

func (o *Object) Something(val interface{}) {
    o.A = 102
    // some other business logic under test

    o.SomethingElse(o.C, val)
}

//...

func (o *Object) Process(val interface{}) interface{} { 
    // some business logic

    return 43 // or something else. no me importa ya
}

//...

func (o *Object) SomethingElse(iPtr *interface{}, val interface{}) { 

    processedVal := o.Process(val)
    if iPtr == nil { 
        iPtr = new(interface{})
    }

    *iPtr = val
}

In writing a test against Object.Something, we should not need to care about what's happening in SomethingElse or the Process invoked from within. Is there any way, in Golang, to isolate these dependencies?

In go you can make functions private (they can only called from the same package) if you write the first letter in lowercase.

If you write the first letter in uppercase you can call the function from everywhere

My understanding of spying is that a single method of an object is faked or mocked while others are not. That's not possible in Go. But you can fake or mock your entire dependencies using interfaces.

In order to fake the SomethingElse method you would have to put it on another struct separate from your Object struct. The Object struct would also need an interface with the SomethingElse method.

type Object struct {
    A     int
    elser Elser
}

func (o *Object) Something() {
    // o.A = 102
    o.elser.SomethingElse()
}

type Elser interface {
    SomethingElse()
}

Now you can test the Object behavior by creating a fake that implements the SomethingElse method:

type fakeElser struct {
    somethingElseWasCalled bool
}

func (f *fakeElser) SomethingElse() {
    f.somethingElseWasCalled = true
}

func TestSomething(t *testing.T) {
    fake := &fakeElser{}
    o := &Object{
        elser: fake,
    }
    o.Something()

    if o.A != 102 {
        t.Errorf("expected A to be %d", 102)
    }

    if !fake.somethingElseWasCalled {
        t.Error("expected SomethingElse to be called")
    }
}

https://play.golang.org/p/RdmbM6Sj5qU