I have the file util.go:
func Foo(service *SomeService) error {
return helper(service)
}
func helper(service *SomeService) error {
...
}
I'm writing unit tests using testify, starting with Foo. I want to:
mock helper
assert mocked helper was called 1 time
I saw some promising solutions at https://stackoverflow.com/a/19168875/1661745, but not sure about them:
Method 1: pass helper as parameter of Foo. My doubt: testify needs a Mock struct to AssertNumberOfCalls, and here there is no struct.
Method 2: create a struct for Foo. My doubt: I don't know if it makes sense to make a struct for utils. Also requires more refactoring since callers of Foo would need a utils struct.
What's the best way to do this?
If you just want to test the args being called in helper, this is an approach that I have been using. The same test will also prove that your helper was called exactly once.
// Code
var originalFn = func(arg1, arg2 string) {
...
}
func Foo() {
originalFn(arg1,arg2)
}
// Tests
func TestFoo(t *testing.T) {
tempFn := originalFn
var fnArgs []string
originalFn = func(arg1, arg2) {
fnArgs = append(fnArgs, []string{arg1, arg2})
}
defer originalFn = tempFn
tests := []struct{
expected []string
}{
{
expected: []string{"arg1", "arg2"},
},
}
for _, tt:= range tests {
fnArgs := make([]string, 0)
Foo()
assert.Equal(t, tt.expected, fnArgs)
}
}
Related
Let's say I have this code and I want to create a test for Foo()
The important part it Foo makes a call to Bar
package main
type MyInterface interface {
Foo() error
Bar() error
}
type MyStruct struct {
}
func NewMyStruct() MyInterface{
return &MyStruct{}
}
func (m *MyStruct) Foo() error {
// do something
m.Bar()
// do something else
return nil
}
func (m *MyStruct) Bar() error {
// do something
return nil
}
Is it possible to create a test for this where I can mock the behaviour of Bar before I run Foo? or am I doing something fundamentally wrong?
I can see that if I extracted Bar into its own service I would mock it that way but that also doesn't feel right.
Any insights or links to documentation would be great.
You should be able to achieve what you need with a couple of changes. First, let me present the code and then I'll walk you through all of the relevant changes.
main.go file
package main
type MyInterface interface {
Foo() error
Bar() error
}
type MyStruct struct {
DS MyInterface
}
// here you've to depend upon an interface and return a pointer to a struct
func NewMyStruct(ds MyInterface) *MyStruct {
return &MyStruct{
DS: ds,
}
}
func (m *MyStruct) Foo() error {
// do something
m.DS.Bar()
// do something else
return nil
}
func (m *MyStruct) Bar() error {
// do something
return nil
}
func main() {}
Here, I changed a couple of things in order to be able to successfully mock our dependencies. Let me recap them:
The MyStruct has a dependency of type MyInterface
The function NewMyStruct accepts the interface as parameter and returns a pointer to the MyStruct struct
In the Foo method, we're going to rely on the DS field of our pointer receiver type instance
Now, let's switch to the test file.
main_test.go file
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// 1. declare mock
type myStructMock struct {
mock.Mock
}
// 2. implement the interface
func (m *myStructMock) Foo() error {
args := m.Called()
return args.Error(0)
}
func (m *myStructMock) Bar() error {
args := m.Called()
return args.Error(0)
}
func TestFoo(t *testing.T) {
// 3. instantiate/setup mock
myStructMock := new(myStructMock)
myStructMock.On("Bar").Return(nil).Times(1)
sut := NewMyStruct(myStructMock)
err := sut.Foo()
// 4. check that all expectations were met on the mock
assert.Nil(t, err)
assert.True(t, myStructMock.AssertExpectations(t))
}
Here, I found it best to add comments within the code to give you a chronological order of what's going on. The idea is that the real system tested (e.g. the sut variable) is relying on mock instead of actual implementations. Thanks to the method Times, we make sure that the Bar method is called once.
I always used this approach when it comes to testing production code and I find it pretty flexible and amazing!
Let me know if this helps you or if you still need something else, thanks!
I am using gomock, and I have this piece of example code that I wish to test.
type StructA struct {
client map[string]Foo
}
type Foo interface {
foo.methodFoo() string
}
func (a *structA) MethodA(name string) string {
client := a.client[name]
return client.methodFoo()
}
In my test, i've generated a mock for foo, called mockFoo. Used mockgen v1.6.0 to generate the mock for interface foo.
I have the test code as:
func Test_MethodA(t *testing.T) {
type fields struct {
client map[string]*mockFoo
}
tests := []struct {
fields fields
want string
}
{
// test cases
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &StructA {
client: tt.fields.client //this has an error, saying that we cannot use map[string]*mockFoo as the type map[string]foo
}
...
})
}
}
TLDR is that map[string]*mockFoo cannot be used as the type map[string]Foo.
var foo1 Foo
var mockFoo1 *mockFoo
foo1 = mockFoo1 // no problem
var fooMap map[string]Foo
var mockFooMap map[string]*mockFoo
fooMap = mockFooMap // problematic
May I know if I'm doing anything wrong here or if this an expected behaviour? Thanks.
Based on your description, Foo is an interface, and *mockFoo implements the Foo interface. Thus, whenever a Foo is required, you can used *mockFoo.
The type map[string]Foo is not the same as the type map[string]*mockFoo. Both are concrete types (they are not interfaces), so you cannot substitute one for the other.
You can, however, use map[string]Foo, and put *mockFoo values into that map, and as far as I can see from your code, that's what you should do. Declare the map as map[string]Foo, and use *mockFoo values in it. If you need to refer to the values of the map as *mockFoo, you can type-assert the map value to get the *mockFoo value, that is:
fooMap=map[string]Foo{}
fooMap["key"]=mockFoo1
...
value:=foomap["key"].(*mockFoo)
I want to mock a property from a struct that uses an interface so I don't get a nil pointer when the function arrives at that point.
This is the code:
type Server struct{
parser: Parser
}
type Parser interface{
SetProvider(p *Provider)
}
func (s *Server) doSomething(){
s.anotherAction()
// ...
// here it crashes because I haven't assigned anything to parser in serverMock
s.parser.SetProvider(&Provider{
name: "foo"
})
}
And this the test code:
var serverMock = &Server{
parser:
}
// mock SetProvider
func (s *Server) SetProvider(p *Provider) {
// some action
}
TestMyCustomTest(){
res, err := serverMock.doSomething()
expected := struct{
hobby: "code",
}
assert.Equal(t, &expected, res)
}
As you see I haven't assigned anything to parser: from var serverMock because I still don't know what should I do to make it work. I cannot assign a mockInterface to that parser field because it'll tell me that the original Server struct requires the Parser interface not a mock one and I think I need the &Server pointer for var serverMock = &Server because it's using other actions like s.anotherAction().
If i understand your intention correctly, you want to test Server's doSomething method and it depends on Parser.SetProvider method. So, what you want, instead of mocking Server, is to create mock struct that satisfies Parser interface and create Server instance that uses it. Here is example of such test:
type mockParser struct {
// You can add field here
}
// mockParser implements SetProvider(p *Provider) method so that it satisfies Parser interface
func (parser *mockParser) SetProvider(provider *Provider) {
// You can do something here
}
TestMyCustomTest(t *testing.T){
parser := mockParser{}
srv := &Server{parser: &parser}
// write your test
assert.Equal(t, ...)
}
I want to wrap goquery.Selection for getting HTML and selector string more conveniently.
To access methods of goquery.Selection, should I implement some helper method such as Get() on the following code?
type MySelection goquery.Selection
// Without this helper method, I should always use type conversion
// to use goquery.Selection's methods.
func (s *MySelection) Get() *goquery.Selection {
sel := s.(goquery.Selection)
return sel
}
func (s *MySelection) HTML() string {
// html, _ := s.Html() <- error
html, _ := s.Get().Html()
return html
}
func (s *MySelection) String() string {
return fmt.Sprintf("%v#%v.%v",
goquery.NodeName(s.Get()),
s.Get().AttrOr("id", "(undefined)"),
s.Get().AttrOr("class", "(undefined)"))
}
Are there better ways to handle this situation?
You also can embed
type MySelection struct {
goquery.Selection
some payload //if needed
}
and you will have goquery.Selection methods for MySelection for free and can to add or overwrite some.
Well, there are several ways to "handle this." But don't name it Get(): it isn't idiomatic.
From a best-practices perspective, I would recommend:
Decouple their code from your code.
Implementing an Anti-Corruption Layer (a wrapper that wraps their package)
The reasons for this is many. But for Go, it's best to keep it simple - which boils down to one question: do you want to unit test your code?
If the answer is yes, then I would never use a 3rd party package directly. I'd wrap their package with my own interface. Then, use use (inject) that interface throughout all of my code so to allow me to mock it up in unit tests.
Again there are several patterns and opinions; but, i am going to show this one of a wrapper allowing for unit testing.
goquery_wrapper.go
package mypackage
import (
"path/to/goquery.Selection"
)
var _mySelector *mySelector // Go stdlib uses underscores for private types
type mySelector interface {
Html() string
...
}
type MySelector struct {
}
func (ms *MySelector) Html() {
// your custom version
}
// initialize the global var with your wrapper
func init() {
_mySelector = &MySelector{ ... }
}
foo.go
package mypackage
func Foo() {
// uses the global var initialized with init()
data := _mySelector.Html()
// IoC using D.I. through constructors
obj := NewSomething(_mySelector)
// IoC using D.I. through methods
result := bar.Process(_mySelector, "input data")
}
bar_test.go
package mypackage
import (
"testing"
)
type mockSelector struct {
HtmlWasCalled bool
HtmlReturnsThis string
}
func (ms mockSelector) Html() string {
ms.HtmlWasCalled = true
return ms.HtmlReturnsThis
}
func TestBar(t *testing.T) {
// arrange
// override your global var
oldMS := _mySelector
_mySelector := &mockSelector{
HtmlReturnsThis: "<b>success</b>",
}
// act
// since foo.Bar is using the global var, it now uses
// our mock we set above.
result := foo.Bar("sample input")
// assert
if result != expected {
t.Fail()
}
// put it back the way it was
_mySelector = oldMS
}
func TestFoo(t *testing.T) {
// arrange
mock := &mockSelector{
HtmlReturnsThis: "<b>success</b>",
}
// act
// or, just inject your mock if using IoC
result := bar.Process(mock, "sample input")
// assert
...
}
This decouples me from having to deal with the 3rd party package nuances during unit testing. Works well, except when the API of the package is huge. Then, I question even why I am using the package to begin with if it is that complicated.
I understand that Go doesn't have traditional OOP concepts. However, I'd love to know whether there is a better way for designing a "constructor" as I've done it in my code snippet below:
type myOwnRouter struct {
}
func (mor *myOwnRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from my own Router!")
}
func newMyOwnRouter() *myOwnRouter {
return &myOwnRouter{}
}
func init() {
http.Handle("/", newMyOwnRouter())
...
}
I basically would like to get rid of the "stand alone" newMyOwnRouter() function and have it as part of the struct itself, for example I'd like to be able to do something like:
http.Handle("/", myOwnRouter.Router)
Is that doable?
The defacto standard pattern is a function calle New
package matrix
function NewMatrix(rows, cols int) *matrix {
m := new(matrix)
m.rows = rows
m.cols = cols
m.elems = make([]float, rows*cols)
return m
}
Of course the construct function must be a Public one, to be called outside of the package.
More about constructor pattern here
In your case looks like you want a Sigleton package then this is the pattern:
package singleton
type myOwnRouter struct {
}
var instantiated *myOwnRouter = nil
func NewMyOwnRouter() * myOwnRouter {
if instantiated == nil {
instantiated = new(myOwnRouter);
}
return instantiated;
}