How to mock functions in the golang

Hi,

I want to mock the functions while i am testing an API , it uses functions of different package but i want to mock them using testify/mock or some other technique in Golang.
Please suggest if we can do this , Is it possible to mock other package functions or not .

API am thinking to do a Unit Testing

func EmailTemplate(c echo.Context) error {

    wc  := core.GetWebContext(c)

    eTplUID := wc.Param("etpl_id")
    if len(eTplUID) == 0 {
            e := errors.Wrap(nil, "email template uid is required")
            wc.Logger().Error(e)
            //return e

    }

    **//Want to mock This function**
    u, err := service.GetUserForRequest(wc)  
    if err != nil {
            //return wc.JSON(http.StatusUnauthorized, model.NewErrorResponse("error in fetching user details"))
    }

     **// Want to mock this function**
     appCtx := core.BuildAppContext(context.Background(), wc.Registry)

    **// Want to mock this function**
    err = service.DeleteEmailTemplate(appCtx, eTplUID, u.OrgID)
    if err != nil {
      return wc.JSON(http.StatusInternalServerError, model.NewErrorResponse().AddError(err))
    }

}

API with which I am planing to test the above API

func TestEmailTemplateDelete(t *testing.T) {

    e := echo.New()
    req := httptest.NewRequest(http.MethodGet, "/", nil)
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)
    c.SetPath("/test/email_template/")
    c.SetParamNames("etpl_id")
    c.SetParamValues("12")

    if assert.NoError(t, EmailTemplateDelete(c)) {
            assert.Equal(t, http.StatusOK, rec.Code)
            //assert.Equal(t, userJSON, strings.TrimSpace(rec.Body.String()))
    }

}

I am really puzzled to test it, Please suggest the way to test it

Regards
Amit Jain

You mean having endpoints or models in other files?

Create UserService and EmailService interfaces,

type UserService interface{
    GetUserForRequest(core.WebContext)(user, error)
}
type DefaultUserService struct{

}
func (userService *DefaultUserServer) GetUserForRequest(core.WebContext)(user, error){
   //some codes
   return user{}, nil
}

Make core.BuildAppContext assignable variable in the package and then set it via a setter. Or convert it to an interface: AppBuilder, to demonstrate how to do it with functions(I would do it with interfaces and dependency injector):

package core
type BuildAppContext func(context.Context, Registry)
var defaultAppBuilder BuildAppContext

func SetAppBuilder(f BuildAppContext){
   defaultAppBuilder = f
}
func init(){
  defaultAppBuilder = func (context.Context, Registery){
        // some code here
   }
}

Testing

// Mock UserService
type MockUserService struct{

}
func (userService *typeMockUserService) GetUserForRequest(core.WebContext)(user, error){
   return user{id:1}, nil
}
func TestUserEmail(t *testing.T){
   userServer := UserServer{}
   userServer.UserService = &MockUserService{}
   //userServer.EmailService = &MockEmailService{} not implemented

   core.SetAppBuilder(func (context.Context, Registery){
       // some code
   })
    e := echo.New()
    req := httptest.NewRequest(http.MethodGet, "/", nil)
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)
    c.SetPath("/test/email_template/")
    c.SetParamNames("etpl_id")
    c.SetParamValues("12")

    if assert.NoError(t, userServer.EmailTemplateDelete(c)) {
            assert.Equal(t, http.StatusOK, rec.Code)
            //assert.Equal(t, userJSON, strings.TrimSpace(rec.Body.String()))
    }
}

Change your handler, attach it to UserServer which carries all the dependencies and configurations, another option is to use global variables but not recommended, look for google for more details.

type UserServer struct{
    UserService UserService
   //EmailService EmailService
   
}
func (userServer UserServer) EmailTemplate(c echo.Context) error {
   // some codes
 **//Want to mock This function**
    u, err := userServer.UserService.GetUserForRequest(wc)  
   // some codes
}

I am sharing above code to give some tips to do it, before start implement it I highly recommend you to look google for dependency injection in go API’s .

1 Like

Thanks a lot Ali :slight_smile:

Hello Ali,

I am very new to golang. Switched my career from Linux admin to golang development. I am trying to find some good resources to understand mocking in golang using interfaces, but I keep getting confused from the articles from the internet as I am not able to figure out the pattern. Can you please tell me how do you plan about how to mock? I mean there must be a pattern like we need an interface, a struct, a method, how they must be interconnected, etc. Any helps would be appreciated. Thanks in advance.