assert_called_once() or assert_called_xyz().... equivalent? - unit-testing

It is important to me to be able to assert how many times a fake / mocked method is called in my tests and I'm wondering what is the best way to do this without using something like testify. In my case, the call to the mocked method is the result of some recursive call.
Lets say I have table driven tests with various animals, I want to assert that Hello is actually called for some tests but not for others. In some cases, it should be called more than once for given test (iterating over a slice).
Is it appropriate to just add a counter and make an assertion on that in my table driven test? It seems to me like maybe there is a better way to do this.
If I do add a counter to the hello method... where is it appropriate to deal with and check this. In the fake method itself or in the test etc?
type fakeFarmService struct {
abc.someFarmServiceInterface
}
func (f *fakeFarmService) Hello(ctx context.Context, in *abc.FarmRequest) (*abc.FarmResponse, error) {
if in.GetAnimal() == Monkey {
return &abc.HelloResponse{}, nil
}
return nil, errors.New("an error")
}

I've used the approach of counter on the struct and then asserting it inside the package level unit test multiple times in the past. Still, it's probably only until the level of package, when you would like to test such an internal assertions. I believe it's an accepted way of doing this in Go. Just be careful about properly synchronizing the access to the counter, if you decide to use a global variable or run the tests concurrently.
package main
import (
"fmt"
"sync"
"testing"
)
type fakeable interface {
Hello()
}
type fakeFarmService struct {
mu sync.Mutex
counter int
}
func (f *fakeFarmService) Hello() {
f.mu.Lock()
f.counter++
f.mu.Unlock()
}
func helloCaller(callee fakeable) {
callee.Hello()
}
func TestCallingTheHello(t *testing.T) {
fakeSvc := &fakeFarmService{}
helloCaller(fakeSvc)
helloCaller(fakeSvc)
// we expect that Hello method of fakeable was called 2 times
fakeSvc.mu.Lock()
defer fakeSvc.mu.Unlock()
if c := fakeSvc.counter; c != 2 {
t.Errorf("unexpected call count, want 2, got %d", c)
}
}
func main() {
TestCallingTheHello(&testing.T{})
}
https://play.golang.org/p/RXKuLKIZwc (test error won't work inside the playground)
Some good material on advanced testing in Go
Testing Techniques by Andrew Gerrand
NewStore TechTalk - Advanced Testing with Go by Mitchell Hashimoto

Related

How do we write unit test for a function using goroutine? considering inside function is being used with/without goroutine

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

How to mock a package method in Go?

Let's say I have a package with the following code:
package paths
type FilePath struct {
PathA string
}
func (c FilePath) GetPathA() string {
if err := PathExists(PathA); err != nil {
return ""
}
return PathA + "foo"
}
func PathExists(p string) error {
// call os and file methods
return err
}
How do I mock out the PathExists dependency to test FilePath? Also, method PathExists is being used by a lot of other packages as well. (I am open to suggestions of refactoring this to make it test friendly, keeping the following pointers in mind)
I have come across a few different approaches but none of them seems intuitive or idiomatic to me.
Have a global variable PE := PathExists in the package; in GetPathA, call err := PE(PathA) and in the test overwrite PE with a mock method.
Issue: If test package is something like paths_test, I will have to export PE which allows clients of the package to overwrite it as well.
Make PathExists a field of FilePath and mock the field in test.
Issue: Clients when using the package, will have to initialize PathExists field, or I provide a constructor of the form NewFilePath(PathtA string) which initializes the fields for me. In the actual use case there are a lot of fields, hence this approach fails as well.
Use an interface and embed it within the struct. When client uses it initialize with the actual method and for test mock it.
type PathExistser interface{
PathExists(p string) error
}
type FilePath struct{
PathA string
PathExister
}
type Actual struct{}
func (a Actual) PathExists(p string) error {
return PathExists(p)
}
Issue: Client again needs to provide the right implementation of the interface.
I have learnt of few more approaches doing something simimlar to the above options, such as make the method PathExists an argument for GetPathA, etc. All have the same concerns. Basically, I don't want the users of this package to have to figure out what should be the right input parameter to make sure the struct works as expected. Neither do I want the users to overwrite the behaviour PathExists.
This seems like a very straightforward problem and I seem to be missing something very funamental about go testing or mocking. Any help would be appreciated, thanks.
Method names are just for example. In reality GetPathA or PathExists would be way more complex.
To address the issue from your 1. approach, you can use an internal package which you'll then be able to import in paths_test but clients of your package won't be.
package paths
import (
// ...
"<your_module_path>/internal/osutil"
)
func PathExists(p string) error {
return osutil.PathExists(p)
}
package osutil
var PathExists = func(p string) error {
// call os and file methods
return err
}
// Use a mutex to make sure that if you have
// multiple tests using mockPathExists and running
// in parallel you avoid the possiblity of a data race.
//
// NOTE that the mutex is only useful if *all* of your tests
// use MockPathExists. If only some do while others don't but
// still directly or indirectly cause the paths.PathExists
// function to be invoked then you still can run into a data
// race problem.
var mu sync.Mutex
func MockPathExists(mock func(p string) error) (unmock func()) {
mu.Lock()
original := PathExists
PathExists = mock
return func() {
PathExists = original
mu.Unlock()
}
}
package paths_test
import (
// ...
"<your_module_path>/internal/osutil"
)
func TestPathExists(t *testing.T) {
unmock := osutil.MockPathExists(myPathExistsMockImpl)
defer unmock()
// do your test
}

Golang stretchr testify mock calls to a function within same class

I am pretty new to Golang and writing unit test for a function (I am using stretchr testify for mocks). This function however calls another function in same class. But when unit testing the first function, I want to mock the call to second function because I do not want it to call the second function in real. This was easy in Java, but I am not finding any useful information for this in Go. Here is some code snippet for my functions:
func (p *Prod) GetProducts(name string, request *prod.ProductRequest) (detail *prod.Department, err error) {
....
....
if err = p.getDetails(ctx, detail.Id); err != nil {
logger.Error(err)
return
}
...
...
}
func (p *Prod) GetDetails(name string, Id string) error {
....
....
}
As you can see here, GetProducts is the function that I am trying to unit test and this function calls GetDetails. I would like to mock the call to GetDetails. Is this possible in Go? Do we typically mock such function calls in Go. Is it recommended? If yes, whats the right way to do it?
In my test, I have:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Prod{
...
ds: tt.fields.ds,
}
p.GetProducts("somestring", request)
})
}
This calls the function GetProducts. But now I don't know what changes to make so the call to GetDetails can be mocked. I would appreciate any help on this

How to mock structs with interdependent interface methods

I am having trouble writing unit tests in Go for a rather common use-case/pattern.
Imagine, if you will, something like this:
package main
type Resource struct {
name string
}
type ResourceManager interface {
GetResource(id string) (*Resource, error)
GetAllResources() ([]*Resource, error)
}
type ResourceManagerImpl struct {
}
func (r *ResourceManagerImpl) GetResource(id string) (*Resource, error) {
resource := &Resource{}
var err error
// fetch resource.
// ...
return resource, err
}
func (r *ResourceManagerImpl) GetAllResources() ([]*Resource, error) {
var resources []*Resource
var err error
// for _, id := range ids {
// resource = r.GetResource(id)
// resources = append(resources, resource)
// }
return resources, err
}
It's a common pattern to have the GetAllResources invoke GetResource repeatedly as-needed.
I can use gomock or testify to test all permutations of GetResource. But, when testing GetAllResource, I'd like to mock GetResource. Otherwise, testing would become sort-of-a nightmare. This is how one would do it in easymock or mockito in case of Java using partial mocks. But, it's not clear how the same could be achieved in Golang.
Specifically, I couldn't find how to partially mock the struct. Most suggestions revolve around breaking such structs but in this case, the struct is already at its bare minimum. It seems like a fair ask to not break the ResourceManager interface (into single and multi) for the sake of testing as that would not make much sense and would be kludgy at best and wouldn't scale well as more such methods make into the interface.
This is how I deal with this kind of situation:
func (r *ResourceManagerImpl) GetAllResources() ([]*Resource, error) {
return getAllResources(r)
}
func getAllResources(r ResourceManager) ([]*Resource,error) {
...
}
Then you test getAllResources instead of GetAllResources with a mocked r. If you have a situation where GetAllResources is called from the code and you have to mock GetAllResources, you can do:
var getAllResources=func(r ResourceManager) ([]*Resource,error) {
...
}
And assign getAllResources to a test instance.

Golang Unit Testing: error conditions

How do I test error conditions, & other unexpected code flow, in Golang?
Suppose I have code as follows:
import crypto
func A(args) error {
x, err := crypto.B()
if err != nil {
return err
}
return nil
}
B is some function. I believe that the only way for me to test this failure scenario is to change the value of B for my test (mock it so it returns an error). Things I have tried:
1) monkeypatch the function just before the test and unpatch afterwards.
This was a horrible idea. Caused all sorts of weird issues as the
tests were running.
2) Pass B as an argument to A. This is all well and good but it also
means that I have to change the definition for A and then update
every use of it every time the implementation changes. Furthermore,
A may be using many imported functions and putting them all in the
type definition for A just seems ugly and not idiomatic.
3) Change the value of B for my test, then change it back.
import crypto.B
cryptoB = crypto.B
func A(args) error {
x, err := cryptoB()
if err != nil {
return err
}
...
}
func Test_A(t *testing.T) {
oldB := cryptoB
cryptoB = mockB
// run test
cryptoB = oldB
...
}
I've been using method #3 as it allows me fine grained unit testing control while not creating too much overhead. That said, it's ugly and causes confusion e.g. "Why are we renaming all of the imported functions?".
What should I be doing? Please help me so my codes can be more better :)
Like you, I've never seen a solution to this problem that's totally satisfied me.
In regards to your example 3, remember that you can defer the reset of the cryptoB. This, combined with good naming of the mock functions, would make it clear what you are trying to accomplish. There are obviously still code-style issues with this approach, with having all of your references listed line by line, twice, at the start of your file.
func TestSomething(t *testing.T) {
cryptoB = mockedFunc
defer func() {
cryptoB = crypto.B
}
// Testing goes on here
}
Option 4
The other approach (which I would favor) would be to turn the functions you export into methods of a CryptoA struct. The struct would store whatever dependencies and state it requires. Something like this:
type CryptoA struct {
cryptoB func() error
}
func (a *CryptoA) CryptoA() error {
return a.cryptoB()
}
func NewCryptoA() *CryptoA {
return &CryptoA{
cryptoB: func() error {
return nil
},
}
}
and mocking would be very similar:
func TestSomething(t *testing.T) {
a := NewCryptoA()
a.cryptoB = mockedFunc
// Testing goes on here
}
With this approach you lose some by your API having an extra step for invocation, a := NewCryptoA(), and you still have to name all of your dependencies, but you make gains by having the state of your API specific to each client.
Maybe there is a flaw in your API, and you leak data somewhere unexpected, or there is some state modifications that you don't expect. If you create a new CryptoA for each caller, then maybe the amount of data you leak, or the number of clients with a corrupted state, is limited, and therefore the impact less severe/abusable. I'm obviously spitballing at how this applies to your codebase, but hopefully you can get the idea of how this is a win.
Also, if you want to give the ability for users to specify their own hash algorithm, you can swap it out internally, and since it's private you maintain confidence that the function is up to the standards of your API. Again, I'm obviously spitballing.
I'll be skimming the answers to see if there's an idiomatic way to do this that I'm unaware of.
My preferred approach is usually to make A a method, and store the dependencies in the receiver object. Example:
import crypto;
type CryptoIface interface {
B() (string, error)
}
type standardCrypto struct {}
var _ CryptoIface = &standardCrypto{}
func (c *standardCrypto) B() (string, error) {
return crypto.B()
}
func main() {
crypto = &standardCrypto{}
err = A(crypto, ...)
// stuff
}
func A(crypto CryptoIface, args ...string) error {
result, err := crypto.B()
if err != nil {
return err
}
// do something with result
return nil
}
Then for your tests, you can easily create a mock version of the CryptoIface:
type mockCrypto struct {
Bfunc func(args ...string) error
}
func (c *mockCrypto) B(args ...string) error {
return c.Bfunc(args...)
}
func TestA(t *testing.T) {
c := &mockCrypto{
Bfunc: func(_ ...string) error {
return errors.New("test error")
}
}
err := A(c)
if err.String() != "test error" {
t.Errorf("Unexpected error: %s", err)
}
}
This approach is usually most useful for large projects or APIs where it makes sense to include a number of methods on a single object. Use your discretion. For smaller cases, this will be overkill.