Golang

Unit-tests

How You Can Make It Easy To Write Unit-Tests In Golang

When I started to write unit-tests in golang at first it wasn't easy and it was taking much time. I didn't know specific tools, technique and libraries to make easy writing of tests. Mocking interfaces was scary and caused a lot of confusion as the implemented interfaces were turned into a sprawling tree of ifs. All this led to such tests becoming difficult to maintain. Over time, I found a package testify of tools that make easy the writing of tests and also GoLand (IDE to golang) which allow you generate interface implementation. Let me show you example of that. Let's say we need to get the user data, we have the API client for that. We need to make for this client an interface and data structure and a simple function that helps us get a user.

go
type User struct {
  ID    string
  Email string
}

type SomeAPIClient interface {
  GetUser(usedId string) (*User, error)
}

func getUser(c SomeAPIClient, userID string) (*User, error) {
  return c.GetUser(userID)
}

Now this functionality can be covered with tests. First we implement our client.

go
type FakeClient struct {
  mock.Mock
}

As you can see, I have added mock.Mock to the structure so that I can mock methods when writing tests.

Now we need to implement interface GetUser we can do it via GoLand using shortkey Ctrl+I or write this

go
func (f FakeClient) GetUser(usedId string) (*User, error) {
  panic("implement me")
}

It is still raw and we need to supplement it so that our function can call this method.

go
func (f FakeClient) GetUser(usedId string) (*User, error) {
  args := f.Called(usedId)
  if args.Get(0) == nil {
    return nil, args.Error(1)
  }
  return args.Get(0).(*User), args.Error(1)
}

This implementation calls the necessary mock object, checks if it is empty, if everything is ok, then returns it.

Now let's just write our unit test.

go
func TestClient(t *testing.T) {

  assert := assert.New(t)
  testClient := new(FakeClient)

  testClient.On("GetUser", "error").Return(nil, errors.New("error"))
  u, err := getUser(testClient, "error")

  assert.Nil(u)
  assert.EqualError(err, "error")
  testClient.AssertExpectations(t)

}

What do we do here? We create a new client of API, then mock our method and in the end we check to see if everything worked out correctly.

go
Test run show us

=== RUN   TestClient
TestClient: user_test.go:32: PASS: GetUser(string)
--- PASS: TestClient (0.00s)
PASS

Add a couple more lines to our test to check we get a user

go
testUser := &User{ID: "user"}
testClient.On("GetUser", "user").Return(testUser, nil)

u, err = getUser(testClient, "user")

assert.Equal(testUser, u)
assert.Nil(err)

You can look at the example code here

27 MAR, 2020

6 top soft skills for QA

Not all skills needed to be a good QA are technical. In the long run, the lack of so-called “soft” skills costs the team in general and QA engineer in particular more expensive than the lack of technical knowledges.

13 MAR, 2020

Speaking from mixing roles experience

Not the “best practice” like combining of several roles in the single one person could be very effective for a small team where extra team-member adding may leads to misunderstanding and loss of information.

28 FEB, 2018

Vue.js and TypeScript Problems Collection

I believe that TypeScript will give you a lot of advantages and if you will invest some time in learning, it will definitely give you outcomes in future. So I decided to migrate small Vue.js 2 application on TypeScript. At first, I wasn't prepared to fac

Help Ukraine to stop russian aggression