Golang: Mock an interface method before Init method is called - go

How can I mock something that gets called in a package init() method?
For example:
main.go
var myService MyService = myservicepkg.New()
func init(){
response := myService.get()
}
func otherMethod(){
//do something
}
maintest.go
func Test_otherMethod(){
ctrl := NewController(t)
defer ctrl.Finish()
myServiceMock = myservicepkg.NewMock(myService)
myServiceMock.EXPECT().get().return("success")
}
The problem is that init() is called before the service is replaced by the mock.

This is the issue of work with a mutable global state.
My advice is to add a flag to not run this on certain conditions or expose a private function that can recover/update this global variable in an internal test.
This reflects your design: if it is complicate to test, perhaps you should refactor.
Create an object Application with a field Service, created on the constructor/builder/factory will be easier to test.
The usage of init is very delicate. Besides register a driver into sql packages, I never use it (perhaps to handle flags).
Perhaps you can add more OO to your design

You will need to call the otherMethod() inside init(). It can't be called before init() otherwise.

I found a workaround, you can prevent the init code from being executed in your test and test the method in isolation like this:
func init(){
if len(os.Args) > 0 && strings.HasSuffix(os.Args[0], ".test") {
log.Printf("skipping jwt.init() for testing")
} else if len(os.Args) > 1 && strings.HasSuffix(os.Args[1], "-test.run") {
log.Printf("skipping jwt.init() for testing")
} else {
response := myService.get()
}
}
This will prevent the init service calls from being called.

Related

How to Mock inner methods in GoLang

e.g
type test struct { // few fields}
func (t *test) createresource(res1 string,res2 string)error {
//doing some task
t.createsubresource(res1)
}
func (t *test)createsubresource(res1 string)error{
//perform some task
}
I want to write test function for createresource , how can I mock t.createsubresource(res1) call. This is legacy code and I don't have permission to modify any above function.
Your mock can be done using interfaces, as for example:
main.go
package main
type TestInterface interface {
CreateResource(res1 string, res2 string) error
CreateSubresource (res1 string) error
}
func main() {
DoSomething(new(Test))
}
func DoSomething(t TestInterface) {
t.CreateResource()
}
main_test.go
package main
import "testing"
type TestMock struct {}
func (tm *TestMock) CreateResource(res1 string, res2 string) error {
return nil
}
func (tm *TestMock) CreateSubresource(res1 string) error {
return nil
}
func TestDoSomething(t *testing.T) {
err := DoSomething(new(TestMock))
//... do your assertions
}
Why does it works like that?
Calling a function that depends on a specific structure does not allow you to inject alternatives to it, that's why a solution using interface needs to be created. By having an interface, just implement a new structure that matches that interface and pass it as a dependency injection to the procedure that will be tested.
Also, check this out:
There is no easy way, by default, to just point your original structure and tell Go to make a mock from it. Maybe some 3rd party lib can do it (but I didn't saw that yet).
In go, public and private declarations are defined by the first letter as uppercase. By the lower cases declarations in your sample I've noticed that everything is private.
Usually it is not a good practice to test private methods. There are a lot of discussions about this topic, you can take a look in this one here
There are also some support libs to make assertions and mocks like for example stretchr/testify, please make a research first.
I hope that it helps you.

Having a singleton pattern in Go Wire injection

I have a piece of code which is used to load configuration from file and parse it into a struct, I use this configuration quite often and hence I pass it around in the method parameters. Now I as my method parameters are increasing, I am looking at dependency injection and have settle with wire.
Now I have created a provider to load the configuration and an injector to provide the config struct. However each time I call the injection my file is read again, I want that the file is read once and the injection provided as many times as required without any additional loading.
Here is my provider:
// ProvideConfig config provider ...
func ProvideConfig() *config.FileConfig {
var cfp string
flag.StringVar(&cfp, "config", "config.json", "absolute path")
flag.Parse()
return config.Loadconfig(cfp)
}
Injector:
// GetConfig injector ...
func GetConfig() ConfigResource {
wire.Build(ProvideConfig, NewConfigResource)
return ConfigResource{}
}
Now when I call:
injection.GetConfig()
I see that ProvideConfig is called always. I can have a check in the provide config method the determine if the config is already loaded, I am not sure if there is a better way, something like a single instance loader which is built into the wire. I tried looking into the docs but could not find anything relevant.
As far as I'm aware, there's no built in way in wire to specify that a provider is a singleton / should only be called once.
This is accomplished in the usual way in Go, by using sync.Once. Your provider function can be a closure that does the expensive operation only once using sync.Once.Do. This is idiomatic in Go, and doesn't require any special provision from every library that wants to provide "single" loading.
Here's an example without wire:
type Value struct {
id int
msg string
}
type ValueProvider func() *Value
// consumer takes a function that provides a new *Value and consumes
// the *Value provided by it.
func consumer(vp ValueProvider) {
v := vp()
fmt.Printf("Consuming %+v\n", *v)
}
// MakeSingleLoader returns a ValueProvider that creates a value once using an
// expensive operation, and then keeps returning the same value.
func MakeSingleLoader() ValueProvider {
var v *Value
var once sync.Once
return func() *Value {
once.Do(func() {
v = ExpensiveOperation()
})
return v
}
}
// ExpensiveOperation emulates an expensive operation that can take a while
// to run.
func ExpensiveOperation() *Value {
return &Value{id: 1, msg: "hello"}
}
func main() {
sl := MakeSingleLoader()
consumer(sl)
consumer(sl)
consumer(sl)
}
If you're OK with the "singleton" value being a global, this code can be simplified a bit. Otherwise, it only calls ExpensiveOperation once, and keeps the value cached in a local inaccessible outside MakeSingleLoader.

How do I improve the testability of go library methods

I'm writing some code that uses a library called Vault. In this library we have a Client. My code makes use of this Client but I want to be able to easily test the code that uses it. I use only a couple methods from the library so I ended up creating an interface:
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
Now if my code is pointed at this interface everything is easily testable.. Except let's look at the Logical() method. It returns a struct here. My issue is that this Logical struct also has methods on it that allow you to Read, Write, ex:
func (c *Logical) Read(path string) (*Secret, error) {
return c.ReadWithData(path, nil)
}
and these are being used in my project as well to do something like:
{{ VaultClient defined above }}.Logical().Write("something", something)
Here is the issue. The Logical returned from the call to .Logical() has a .Write and .Read method that I can't reach to mock. I don't want all the logic within those methods to run in my tests.
Ideally I'd like to be able to do something similar to what I did above and create an interface for Logical as well. I'm relatively new to Golang, but I'm struggling with the best approach here. From what I can tell that's not possible. Embedding doesn't work like inheritance so it seems like I have to return a Logical. That leaves my code unable to be tested as simply as I would like because all the logic within a Logical's methods can't be mocked.
I'm sort of at a loss here. I have scoured Google for an answer to this but nobody ever talks about this scenario. They only go as far as I went with the initial interface for the client.
Is this a common scenario? Other libraries I've used don't return structs like Logical. Instead they typically just return a bland struct that holds data and has no methods.
package usecasevaultclient
// usecase.go
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
type vaultClient struct {
repo RepoVaultClient
}
// create new injection
func NewVaultClient(repo RepoVaultClient) VaultClient {
return &vaultClient{repo}
}
func(u *vaultClient) Logical() *api.Logical {
// do your logic and call the repo of
u.repo.ReadData()
u.repo.WriteData()
}
func(u *vaultClient) SetToken(v string) {}
func(u *vaultClient) NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
// interfaces.go
type RepoVaultClient interface {
ReadData() error
WriteData() error
}
// repo_vaultclient_mock.go
import "github.com/stretchr/testify/mock"
type MockRepoVaultClient struct {
mock.Mock
}
func (m *MockRepoVaultClient) ReadData() error {
args := m.Called()
return args.Error(0)
}
func (m *MockRepoVaultClient) WriteData() error {
args := m.Called()
return args.Error(0)
}
// vaultClient_test.go
func TestLogicalShouldBeSuccess(t *testing.T) {
mockRepoVaultClient = &MockRepoVaultClient{}
useCase := NewVaultClient(mockRepoVaultClient)
mockRepoVaultClient.On("ReadData").Return(nil)
mockRepoVaultClient.On("WriteData").Return(nil)
// your logics gonna make this response as actual what u implemented
response := useCase.Logical()
assert.Equal(t, expected, response)
}
if you want to test the interface of Logical you need to mock the ReadData and WriteData , with testify/mock so u can defined the respond of return of those methods and you can compare it after you called the new injection of your interface

Using testing.T in TestMain

There are a few test cases I want to run for which there is a need to start a GRPC mock server. I am using gomock library for this. To start the server, I have to pass a variable of type testing.T to this function - gomock.NewController(). Since this is a kind of initialization for all the test cases, I want to do this in TestMain. But TestMain has access to only testing.M So how do I handle this case? Create a new testing.T structure in TestMain? Will it work?
It sounds like you are looking for a BeforeEach pattern. You don't have access to a testing.T object in TestMain because this is something more of a place to do initialization before and after the test suite runs.
There are a few frameworks out there that can give you a BeforeEach cheap:
Ginkgo
Onpar
to name a few.
You could also hand roll your own:
type test struct{
ctrl *gomock.Controller
mockFoo *MockFoo
// ...
}
func beforeEach(t *testing.T) test {
ctrl := gomock.NewController(t)
return test {
ctrl:ctrl,
mockFoo: NewMockFoo(ctrl),
}
}
func TestBar(t *testing.T) {
test := beforeEach(t)
// ...
}
func TestBaz(t *testing.T) {
test := beforeEach(t)
// ...
}

Pointer reference not stored in a struct in my go program

I am new to go-lang and I try to figure out how to work properly with structs and dependency injection. I am a bit stuck because I am not able to properly store a reference to another struct.
Here's my method that generates a CommandController. There is a valid reference to iris.Application.
func ProvideCommandController(application *iris.Application, commandRepository command.CommandRepository) (*interfaces.CommandController, error) {
commandController := interfaces.CommandController{}
commandController.Init(application, commandRepository)
commandController.Start()
return &commandController, nil
}
The struct looks like this:
type CommandController struct {
commandRepository command.CommandRepository
app *iris.Application
}
func (c CommandController) Init(app *iris.Application, repository command.CommandRepository) {
c.app = app
c.commandRepository = repository
}
func (c CommandController) Start() {
c.app.Get("/command", c.readAll)
c.app.Get("/command/{id:string}/execute", c.executeCommand)
c.app.Run(iris.Addr(":8080"))
}
When the ProvideCommandController function gets executed I can debug and observe that all references look good. Unfortunately, commandController.Start()fails because of c.app is nil.
What piece of understanding do I miss? Somehow, the stored reference get's deleted between the Init and the Start function call.
Thanks in advance :)
Change
func (c CommandController) Init(app *iris.Application, repository command.CommandRepository)
to
func (c *CommandController) Init(app *iris.Application, repository command.CommandRepository)
since Init receives c by value in your version, any changes it makes to c don't appear outside of the Init method.

Resources