Gabriel Araújo
Gabriel Araújo

Reputation: 111

How do I stub sqlmock to never return error?

I can not test the function NewDao that uses a database arbitrarily. I want to check whether the returned Dao have neither nil client nor nil product.

type Dao struct {
  client ClientDao
  product ProductDao
}

func (d *Dao) Client() ClientDao {
  return d.client
}

func (d *Dao) Product() ProductDao {
  return d.product
}

func NewDao(db *sql.DB) (*Dao, error) {
  if db == nil {
    return nil, errors.New("Can't create a dao from nil database")
  }
  client, err := newClientDao(db) // Uses db arbitrarily
  if err != nil {
    return nil, err
  }
  product, err := newProductDao(db) // Uses db arbitrarily
  if err != nil {
    return nil, err
  }
  return &Dao{client, product}, nil
}

I test NewDao() using sqlmock but it always fails because I don't know what the mock needs to expect.

func TestNewDao(t *testing.T) {
  db, mock, err := sqlmock.New()
  if err != nil {
    t.Fatal("Can't create database for test dao")
  }

  // How to set mock to expect anything and never fail?
  // mock.ExpectQuery(any) ?

  dao, err := NewDao(db)

  // err is never nil, because mock has no expectations

  if err != nil {
    t.Fatal("Can't create dao for test dao.User %q", err)
  }
  if dao.User() == nil {
    t.Fatalf("User dao is nil")
  }
  if dao.Client() == nil {
    t.Fatalf("Client dao is nil")
  }
}

Does any one know how to stub the sqlmock for achieving my purpose? Or can appoint an alternative to sqlmock lib?

Upvotes: 1

Views: 409

Answers (2)

mkopriva
mkopriva

Reputation: 38343

Your Dao.Client and Dao.Product methods themselves make no calls to any dependency and because of that there is nothing for you to mock. There is no point in using a mock for testing these two methods.

And although testing one liners like these may not be the most sensible thing to do, if you want to test them anyway you just need to make sure that the value they return equals the value of the field that they're supposed to return.

func TestDaoClient(t *testing.T) {
    var client ClientDao // TODO: prepare a client dao value for test

    tests := []struct{
        name string
        dao *Dao
        want ClientDao
    }{{
        name: "should return client dao",
        dao: &Dao{client: client},
        want: client,
    }, {
        name: "should return nil",
        dao: &Dao{client: nil},
        want: nil,
    }}

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := tt.dao.Client(); !reflect.DeepEqual(got, tt.want) {
                t.Errorf("client got=%v, want=%v", got, tt.want)
            }
        })    
    }
}

Now you can do the same for the Dao.Product method.

Upvotes: 0

David Budworth
David Budworth

Reputation: 11646

You are missing the second item in your last return in NewDao:

return &Dao{client, product}

should be:

return &Dao{client, product}, nil

Return statements have to "return" all the things declared in the function header.

Upvotes: 1

Related Questions