How to initialize default implementations for Mock interfaces in Structs?

Hi,
To facilitate testing things my Go struct has a Clock interface which enables me to avoid having to call time.Now() but obviously everyone who does a &MyStruct{} directly will receive a nil panic as my clock is not set:

type Clock interface { 
   Now() time.Time
}

type realClock struct {}

func (realClock) Now() time.Time { return time.Now() }

type MyStruct struct {
  clock Clock
}

func (m *MyStruct) Foo() {
  fmt.Printf("The time is %v", m.clock.Now())
}

If anyone were to init this struct incorrectly it would blow up:

m := &MyStruct{}
m.Foo() // => Panic

The way I do it right now is having a New func that inits the struct correctly. But this then is really inconvenient if we need to set a bunch of properties on the struct as they have to be parameters of the struct…

It’s also a bit weird as my struct is visible to other packages and I can’t really prevent anyone from initializing it. Obviously having a public interface and lowercasing the struct would be better, but still this is a bit weird…

What is the best practice around these cases?
Thanks for your help

greetings Daniel

If the zero value of a struct field (in this case, the nil Clock interface) is not useful, you would indeed need a constructor. (See the implementations of io.Reader, for example. They always have a constructor, e.g. bufio.NewReader() or os.Open().)

There are ways to address the requirement of setting properties via the constructor, e.g. functional options. However, as long as the structure is visible to package clients, the problem of insufficient initialization remains.

1 Like

Thanks a lot… That’s what I suspected and it feels a bit weird… But I’ll see where if this ends up being a problem in the long run or not…

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.