DATA-DOG / go-sqlmock

Sql mock driver for golang to test database interactions
Other
6.05k stars 406 forks source link

write unit test with this #341

Open minhthinh27 opened 2 weeks ago

minhthinh27 commented 2 weeks ago

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?