When I try to unit test a function as below, where extern_pkg is an external package to be mocked:
import "extern_pkg"
func MyFunc() {
...
extern_pkg.F()
}
func main() {
MyFunc()
}
I read a few blogs, and they all seem to achieve this by modifying prod code with dependency injection. For example, as below:
type exter interface {
F()
}
func MyFunc(e exter) {
...
e.F()
}
type extpkg struct{}
func (extpkg) F() {extern_pkg.F()}
func main() {
epkg := extpkg{}
MyFunc(epkg)
}
Then in test code, create a mock object that satisfies exter interface, and pass to MyFunc as parameter.
My question is:
If the MyFunc function contains many external packages to mock, do I need to DI each one as function parameters? Is it also true for any global variables the function depends on?
var global_var
func MyFunc() {
...
extern_pkg1.F()
...
extern_pkg2.G()
...
extern_pkg3.H()
...
global_var
}
Is there way to avoid modifying prod code?
Thanks!
Try use vars of func types and inject them. It is easier, lesser code and interfaces are not needed. See godif
Related
so i have function without routine
func ContainsWithoutGoroutine() return {
someFunction()
return
}
and there is mock of someFunction
type DummyMock struct {
mock.mock
}
func(t *DummyMock) someFunction() {
//
}
to write the unit test for ContainsWithoutGoroutine we could easily mock someFunction and test it.
and now suppose i added a function with goroutine ContainsGoroutine
func ContainsGoroutine() return {
go func() {
someFunction()
}()
return
}
could not able to write unit test until we update the mock to something like this
type DummyMock struct {
mock.mock
Wg sync.WaitGroup
}
func(t *DummyMock) someFunction() {
defer t.Wg.Done()
//
}
and in the unit test of ContainsGoroutine need to add additional mock.Add(1) mock.Wg.Wait
after that unit test for ContainsGoroutine will work, but ContainsWithoutGoroutine will start failing
i know we could add same mock.Add(1) mock.Wg.Wait for the unit test of ContainsWithoutGoroutine to make it work , which i don't want to do that , As consider for the case where someFunction has been already being used in lot of places where there was no go routine and all that unit tests need to be changed.
is there a better way to structure this or maybe write unit test differently
I have a struct:
type foo struct {
bar mockableInterface // some interface that I can mock
}
func (f *foo) DoSmth1() []interface{} {
return f.bar.Bar()
}
func (f *foo) DoSmth2() []interface{} {
res := f.DoSmth1()
//some code to test
}
Here I have no problem with mocking bar and testing DoSmth1(). But it's not obvious how to test DoSmth2().
Should I rewrite this method to make it testable or rewrite tests somehow?
#mkopriva recommended just to mock Bar() call in DoSmth2() test. But in this case I would rewrite tests for all method that calls DoSmth1() every time it changes. So I've come to the following solution. We can encapsulate this mock logic in one method:
func (s *TestSuite) ExpectDoSmth1(times int, in, out []interface{}) {
s.barMock.Expect().Bar(in...).Times(times).Return(out...)
}
This way we can change only this method if DoSmth1() implementation changes, till its API stays the same
I have a piece of code which accepts an io.Writer implementation as an argument.
func printSummary(writer io.Writer) {
// Implementation of the 'printSummary' method goes here.
}
Now, I can easily create a mock to create a unit test.
This would look like the following:
type ioWriterMock struct {
writtenBytes []byte
}
func (writer *ioWriterMock) Write(p []byte) (int, error) {
writer.writtenBytes = append(writer.writtenBytes, p...)
return 0, nil
}
However, this does mean that I need to declare my mock outside of my unit test, which makes it available in the whole package.
I would like to create my test, and that everything that my test depends on is inside the test.
This for the simple reason that everything is in one place and that I don't need to scan different files in my package to find the different parts that are required for my test.
In a unit test, you can create a struct and define functions.
This is done using the following approach:
func TestParse(t *testing.T) {
type utCase struct {
name string
summary string
expectedWrittenBytes []byte
}
createUtCase := func(name, summary string, expWrittenBytes []byte) utCase {
retVal := new(utCase)
retVal.name = name
retVal.summary = summary
retVal.expectedWrittenBytes = expWrittenBytes
return *retVal
}
}
So embedding the io.Writer mock in the unit test can be done in the following way:
func TestParse(t *testing.T) {
type ioWriterMock struct {
writtenBytes []byte
}
}
One thing which I don't find is how I'm able to implement the io.Writer interface on that type.
As suggested by #mkopriva, put the ioWriterMock definition next to the TestParse function in the _test.go file. In go, it is not allowed to put the definition of a function inside another function. You can only define the struct type in a function.
By defining the ioWriterMock type and Write method inside the test file, it will only be visible during test execution. It won't be present and thus visible when using the package outside of a test.
Also, considering the given example, a bytes.Buffer would be a good free substitute to your ioWriterMock as suggested by #Flimzy.
Somewhat of a golang beginner, but I've worked with testing frameworks before. How do I go about mocking out and faking what a dependent method returns without injecting the dependency? The reason why I don't want to use dependency injection is because there are many external package methods that are being used and injecting all of the methods in the constructor is unwieldy.
I've searched for this online/stackoverflow and the solution is to always use dependency injection. Sometimes that is not a viable option.
Here's what I'm trying to do code-wise:
b/b_test.go
package b
func TestResults(t *testing.T) {
t.Run("Test", func(t *testing.T) {
b := NewB()
// How do I mock out and fake a.DoSomething() to be
// "complete" instead of whats in the code right now?
result = b.Results()
assert.Equal(t, "complete", result)
}
}
b/b.go
package b
import "a"
type B struct {}
func NewB() B {
return &B{}
}
func (b B) Results() {
return a.DoSomething()
}
a/a.go
package a
func DoSomething() {
return "done"
}
Thanks!
You can use conditional compilation with build tags
a/a.go
// +build !mock
package a
func DoSomething() {
return "done"
}
a/a_mock.go
// +build mock
package a
func DoSomething() { // Insert fake implementation here
return "complete"
}
$ go test -tags mock
One way to do so would be to create a variable with the function you want to call, so include the following in b/b.go:
var doSomething = a.DoSomething
func (b B) Results() {
return doSomething()
}
Now in b_test.go you can do this:
func TestPrintResults(t *testing.T) {
origDoSomething := doSomething
defer func() { doSomething = origDoSomething }
doSomething = func() {
// Insert fake implementation here
}
b := NewB()
result = b.Results()
assert.Equal(t, "complete", result)
}
I'm not sure if I don't understand your objection to dependency injection, but interfaces can be used to make dependency injection relatively painless. In particular existing code does not need to be modified.
You could try aliasing the package name to a global variable that implements an interface that matches the external package's functions. This has the advantage of not requiring inline changes where package "a" is used.
The idea revolves around creating an interface for the functions you need from the external package, a pass-through implementation of that interface for the default behavior and a mock implementation for testing. At the beginning of a test just replace the global variable with the mock.
b/a_interface.go
package b
import (
aa "a" // alias the "a" package
)
// global variable that mimics the external package "a"
var a aType
// internal interface for `a` package functions (i.e. `DoSomething()`)
type aDoer interface {
DoSomething() string
}
// default implementation of the aDoer interface
type aType struct{}
func (aType) DoSomething() string {
// just pass-through to package "a"
return aa.DoSomething()
}
b/b.go - is unmodified other then removing the import:
package b
type B struct{}
func NewB() B {
return B{}
}
func (b B) Results() string{
// now `a` is a global variable not a package.
return a.DoSomething()
}
b/b_test.go
package b
import (
"testing"
"github.com/stretchr/testify/assert"
)
// mock implementation of aDoer interface
type aMock struct{}
func (aMock) DoSomething() string {
return "complete"
}
func TestResults(t *testing.T) {
a = aMock{} // <- replace the default with the mock
b := NewB()
result = b.Results()
assert.Equal(t, "complete", result)
}
It's a bit on the sneaky side, so you'll probably want to make clear comments about what's going on.
I'm working with Golang, and currently I'm doing some fun unit test with Testify, my file look like this
type myStruct struct {
field_1 string
}
func (self *myStruct) writeFirst() {
//doing something
//modify field_1
self.writeSecond()
}
func (self *myStruct) writeSecond() {
//doing something
}
In this case I'm testing writeFirst() but I'm trying to replace writeSecond() because it is using http stuff that I don't want to use because it access to internet.
I think that use a second struct and set myStruct as anonymous field will be the solution, but it's not working because me second struct and myStruct have a diferent context.
In this case I can't use mocks cause writeSecond is a method of the struct.
My test case looks like this:
func TestWriteFirst(t *testing.T) {
myStc := myStruct{}
assert.Equal(t,"My response", myStc.field_1)
}
All that I want is testing writeFirst without pass to writeSecond()
To illustrate the kind of refactoring mentioned by Not-a-Golfer in the comments, you could consider calling your second function only on an instance that is an interface:
type F2er interface {
Func2()
}
type S struct{ _f2 F2er }
var s = &S{}
func (s *S) f2() F2er {
if s._f2 == nil {
return s
}
return s._f2
}
func (s *S) Func1() {
fmt.Println("s.Func1")
s.f2().Func2()
}
Here: Func1 calls Func2 on s.f2(), not directly s.
If nothing has been set in s, s.f2() returns... itself: s
if s._f2 was replaced by any other struct which implements Func2, s.f2() returns that instance instead of itself.
See a complete example in this playground script.
Output:
TestFunc1
s.Func1
s.Func2
TestFunc1bis
s.Func1
testS.Func2 <=== different Func2 call