go-sqlmock icon indicating copy to clipboard operation
go-sqlmock copied to clipboard

write unit test with this

Open minhthinh27 opened this issue 1 year ago • 0 comments
trafficstars

I implement code with dependency injection Like this:

article.go

type IArticleRepo interface {
	List() ([]*entity.Article, error)
	Detail(id uint) (*entity.Article, error)
	Create(item *entity.Article) error
	Update(id uint, items map[string]interface{}) error
	Delete(ids []uint) error
}

type articleRepo struct {
	db container.IDatabaseProvider
}

func (d *articleRepo) List() ([]*entity.Article, error) {
	var (
		tx     = d.db.GetDBSlave()
		result []*entity.Article
	)

	if err := tx.Model(&entity.Article{}).
		Find(result).Error; err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, err
		}
	}

	return result, nil
}

func (d *articleRepo) Detail(id uint) (*entity.Article, error) {
	var (
		tx     = d.db.GetDBSlave()
		result = &entity.Article{}
	)

	if err := tx.Model(&entity.Article{}).
		Where("id = ?", id).
		First(result).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("article not found")
		}
		return nil, err
	}

	return result, nil
}

func (d *articleRepo) Create(item *entity.Article) error {
	var (
		tx = d.db.GetDBMain()
	)

	return tx.Create(item).Error
}

func (d *articleRepo) Update(id uint, items map[string]interface{}) error {
	var (
		tx = d.db.GetDBMain()
	)

	if err := tx.Model(&entity.Article{}).
		Where("id = ?", id).
		Updates(items).Error; err != nil {
	}

	if tx.RowsAffected == 0 {
		tx.Rollback()
		return errors.New("article not found")
	}

	return nil
}

func (d *articleRepo) Delete(ids []uint) error {
	var (
		tx = d.db.GetDBMain()
	)

	return tx.Delete(&entity.Article{}, ids).Error
}

func NewArticleRepo(db container.IDatabaseProvider) IArticleRepo {
	return &articleRepo{
		db: db,
	}
}

and my file test article_test.go

type MockDatabaseProvider struct{}

func (m *MockDatabaseProvider) GetDBSlave() *gorm.DB {
	mockDb, _, _ := sqlmock.New()
	dialector := postgres.New(postgres.Config{
		Conn:       mockDb,
		DriverName: "postgres",
	})
	db, _ := gorm.Open(dialector, &gorm.Config{})

	return db
}

func (m *MockDatabaseProvider) GetDBMain() *gorm.DB {
	mockDb, _, _ := sqlmock.New()
	dialector := postgres.New(postgres.Config{
		Conn:       mockDb,
		DriverName: "postgres",
	})
	db, _ := gorm.Open(dialector, &gorm.Config{})

	return db
}

func TestArticleRepo_Create(t *testing.T) {
	mockDB := &MockDatabaseProvider{}

	// Create a test article
	testArticle := &entity.Article{
		Title:  "Test Article",
		Author: "Author",
	}

	repo := NewArticleRepo(mockDB)
	err := repo.Create(testArticle)
	assert.Nil(t, err)
}

=== RUN TestArticleRepo_Create article_test.go:53: Error Trace: /Users/macthinh/project/my-template-with-go/internal/data/article_test.go:53 Error: Expected nil, but got: &errors.errorString{s:"all expectations were already fulfilled, call to database transaction Begin was not expected"} Test: TestArticleRepo_Create --- FAIL: TestArticleRepo_Create (8.79s)

What am I missing?

minhthinh27 avatar Aug 28 '24 16:08 minhthinh27