0
package main

import "fmt"

type I1 interface {
    A() string
    B() string
}

type S1 struct {
    name string
    i    I1
}

func NewS1(name string) *S1 {
    s := &S1{
        name: name,
    }
    s.i = s
    return s
}
func (s *S1) A() string {
    // This is the method I want to override in my tests
    return "A() was called"
}
func (s *S1) B() string {
    return s.i.A()
}

func main() {
    s1 := NewS1("no matter")
    fmt.Println(s1.B())
}
package main

import (
    "log"
    "testing"
)

type S1Mock struct {
    *S1
}

func (*S1Mock) A() string {
    return "A() from mock was called!"
}

func TestS1_B(t *testing.T) {
    s1mock := S1Mock{NewS1("lol")}
    s1mock.i = &s1mock
    if s1mock.B() != "A() from mock was called!" {
        log.Fatal("error")
    }
}

I'm experimenting with Go interfaces and embedding. The following code does exactly what I want it to do, which is to mock the B() method during tests. But in my solution, I'm forced to keep an interface embedded in my S1 struct, which seems awkward (notice the s.i = s in the NewS1 method). Is there a more idiomatic way to achieve this?

Why does the following not work? The A() method from the S1Mock is never invoked.

package main

import "fmt"

type I1 interface {
    A() string
    B() string
}

type S1 struct {
    name string
}

func NewS1(name string) *S1 {
    s := &S1{
        name: name,
    }
    return s
}
func (s *S1) A() string {
    // Doing things this is the method I want to override
    return "A() was called"
}
func (s *S1) B() string {
    return s.A()
}

func main() {
    s1 := NewS1("no matter")
    fmt.Println(s1.B())
}
package main

import (
    "log"
    "testing"
)

type S1Mock struct {
    *S1
}

func (*S1Mock) A() string {

    return "A() from mock was called!"
}

func TestS1_B(t *testing.T) {
    s1mock := S1Mock{NewS1("lol")}
    if s1mock.B() != "A() from mock was called!" {
        log.Fatalf("Wanted %s got %s", "A() from mock was called!", s1mock.B())
    }
}

Miguel F.
  • 11
  • 1
  • 2
    You don't need to keep an embedded interface. The type *S1 implements I1. – Burak Serdar Jun 06 '22 at 21:45
  • @BurakSerdar I edited the question and added an example implementing what I think you are trying to say, but I don't think I'm getting it right, the A() method from the mock is not invoked. – Miguel F. Jun 06 '22 at 21:54
  • 1
    You are trying to implement late binding and override a method. That is not going to work. You can use a function variable in S1 and change it during test. – Burak Serdar Jun 06 '22 at 22:00
  • The best way is not to mock at all. – Volker Jun 07 '22 at 00:37

0 Answers0