mirror of
https://github.com/ForFarmTeam/ForFarm.git
synced 2025-12-18 21:44:08 +01:00
test: add tests for GetByID in inventory repository
This commit is contained in:
parent
98610a9c5e
commit
e7f1f7ab1b
237
backend/internal/repository/postgres_inventory_test.go
Normal file
237
backend/internal/repository/postgres_inventory_test.go
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
package repository_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/forfarm/backend/internal/domain"
|
||||||
|
"github.com/forfarm/backend/internal/repository"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgconn"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockConnection is a mock implementation of the repository.Connection interface.
|
||||||
|
type MockConnection struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockConnection) Exec(ctx context.Context, query string, args ...interface{}) (pgconn.CommandTag, error) {
|
||||||
|
callArgs := []interface{}{ctx, query}
|
||||||
|
callArgs = append(callArgs, args...)
|
||||||
|
ret := m.Called(callArgs...)
|
||||||
|
return ret.Get(0).(pgconn.CommandTag), ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockConnection) Query(ctx context.Context, query string, args ...interface{}) (pgx.Rows, error) {
|
||||||
|
callArgs := []interface{}{ctx, query}
|
||||||
|
callArgs = append(callArgs, args...)
|
||||||
|
ret := m.Called(callArgs...)
|
||||||
|
rows, _ := ret.Get(0).(pgx.Rows)
|
||||||
|
return rows, ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockConnection) QueryRow(ctx context.Context, query string, args ...interface{}) pgx.Row {
|
||||||
|
callArgs := []interface{}{ctx, query}
|
||||||
|
callArgs = append(callArgs, args...)
|
||||||
|
ret := m.Called(callArgs...)
|
||||||
|
return ret.Get(0).(pgx.Row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockConnection) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) {
|
||||||
|
ret := m.Called(ctx, txOptions)
|
||||||
|
return ret.Get(0).(pgx.Tx), ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockRows is a mock implementation of pgx.Rows
|
||||||
|
type MockRows struct {
|
||||||
|
mock.Mock
|
||||||
|
currentIndex int
|
||||||
|
data []map[string]interface{}
|
||||||
|
columns []string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) Next() bool {
|
||||||
|
m.Called()
|
||||||
|
if m.err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
m.currentIndex++
|
||||||
|
return m.currentIndex <= len(m.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) Scan(dest ...interface{}) error {
|
||||||
|
args := m.Called(dest...)
|
||||||
|
if args.Error(0) != nil {
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.currentIndex > len(m.data) || m.currentIndex == 0 {
|
||||||
|
return errors.New("scan called out of bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRow := m.data[m.currentIndex-1]
|
||||||
|
for i, d := range dest {
|
||||||
|
colName := strconv.Itoa(i)
|
||||||
|
if len(m.columns) > i {
|
||||||
|
colName = m.columns[i]
|
||||||
|
}
|
||||||
|
if val, ok := currentRow[colName]; ok {
|
||||||
|
switch ptr := d.(type) {
|
||||||
|
case *string:
|
||||||
|
*ptr = val.(string)
|
||||||
|
case *int:
|
||||||
|
*ptr = val.(int)
|
||||||
|
case *float64:
|
||||||
|
*ptr = val.(float64)
|
||||||
|
case *time.Time:
|
||||||
|
*ptr = val.(time.Time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) Close() {
|
||||||
|
m.Called()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) Err() error {
|
||||||
|
args := m.Called()
|
||||||
|
if args.Error(0) != nil {
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) CommandTag() pgconn.CommandTag {
|
||||||
|
return pgconn.CommandTag{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) Conn() *pgx.Conn {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) FieldDescriptions() []pgconn.FieldDescription {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) RawValues() [][]byte {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockRows) Values() ([]interface{}, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockEventPublisher is a mock implementation of the domain.EventPublisher interface.
|
||||||
|
type MockEventPublisher struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventPublisher) Publish(ctx context.Context, event domain.Event) error {
|
||||||
|
args := m.Called(ctx, event)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGetByID tests the GetByID function of the inventory repository.
|
||||||
|
func TestGetByID(t *testing.T) {
|
||||||
|
mockConn := new(MockConnection)
|
||||||
|
mockRows := new(MockRows)
|
||||||
|
inventoryRepo := repository.NewPostgresInventory(mockConn, nil, nil)
|
||||||
|
|
||||||
|
testID := uuid.New().String()
|
||||||
|
testUserID := uuid.New().String()
|
||||||
|
|
||||||
|
columns := []string{"id", "user_id", "name", "category_id", "quantity", "unit_id", "date_added", "status_id", "created_at", "updated_at", "category_name", "status_name", "unit_name"}
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
// Test: Successful retrieval of an inventory item by ID.
|
||||||
|
mockRows.On("Next").Return(true).Once()
|
||||||
|
mockRows.On("Scan", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
|
||||||
|
mockRows.On("Close").Return().Once()
|
||||||
|
mockRows.On("Err").Return(nil).Once()
|
||||||
|
mockRows.On("CommandTag").Return(pgconn.CommandTag{}).Once()
|
||||||
|
mockRows.On("FieldDescriptions").Return([]pgconn.FieldDescription{}).Once()
|
||||||
|
mockRows.On("RawValues").Return([][]byte{}).Once()
|
||||||
|
mockRows.On("Values").Return([]interface{}{}, nil).Once()
|
||||||
|
|
||||||
|
mockConn.On("Query", mock.Anything, mock.AnythingOfType("string"), testID, testUserID).Return(mockRows, nil).Once()
|
||||||
|
|
||||||
|
mockRows.data = []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"id": testID,
|
||||||
|
"user_id": testUserID,
|
||||||
|
"name": "Test Item",
|
||||||
|
"category_id": 1,
|
||||||
|
"quantity": 10.5,
|
||||||
|
"unit_id": 1,
|
||||||
|
"date_added": time.Now(),
|
||||||
|
"status_id": 1,
|
||||||
|
"created_at": time.Now(),
|
||||||
|
"updated_at": time.Now(),
|
||||||
|
"category_name": "Category Name",
|
||||||
|
"status_name": "Status Name",
|
||||||
|
"unit_name": "Unit Name",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mockRows.columns = columns
|
||||||
|
|
||||||
|
item, err := inventoryRepo.GetByID(context.Background(), testID, testUserID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, testID, item.ID)
|
||||||
|
mockConn.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not found", func(t *testing.T) {
|
||||||
|
// Test: Item not found scenario.
|
||||||
|
mockRows.On("Next").Return(false).Once()
|
||||||
|
mockRows.On("Close").Return().Once()
|
||||||
|
mockRows.On("Err").Return(nil).Once()
|
||||||
|
mockRows.On("CommandTag").Return(pgconn.CommandTag{}).Once()
|
||||||
|
mockRows.On("FieldDescriptions").Return([]pgconn.FieldDescription{}).Once()
|
||||||
|
mockRows.On("RawValues").Return([][]byte{}).Once()
|
||||||
|
mockRows.On("Values").Return([]interface{}{}, nil).Once()
|
||||||
|
|
||||||
|
mockConn.On("Query", mock.Anything, mock.AnythingOfType("string"), testID, testUserID).Return(mockRows, nil).Once()
|
||||||
|
|
||||||
|
_, err := inventoryRepo.GetByID(context.Background(), testID, testUserID)
|
||||||
|
assert.ErrorIs(t, err, domain.ErrNotFound)
|
||||||
|
mockConn.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("query error", func(t *testing.T) {
|
||||||
|
// Test: Database query returns an error.
|
||||||
|
mockConn.On("Query", mock.Anything, mock.AnythingOfType("string"), testID, testUserID).Return(nil, errors.New("database error")).Once()
|
||||||
|
|
||||||
|
_, err := inventoryRepo.GetByID(context.Background(), testID, testUserID)
|
||||||
|
assert.Error(t, err)
|
||||||
|
mockConn.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("scan error", func(t *testing.T) {
|
||||||
|
// Test: Error during row scanning.
|
||||||
|
mockRows.On("Next").Return(true).Once()
|
||||||
|
mockRows.On("Scan", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("scan error")).Once()
|
||||||
|
mockRows.On("Close").Return().Once()
|
||||||
|
mockRows.On("Err").Return(nil).Once()
|
||||||
|
mockRows.On("CommandTag").Return(pgconn.CommandTag{}).Once()
|
||||||
|
mockRows.On("FieldDescriptions").Return([]pgconn.FieldDescription{}).Once()
|
||||||
|
mockRows.On("RawValues").Return([][]byte{}).Once()
|
||||||
|
mockRows.On("Values").Return([]interface{}{}, nil).Once()
|
||||||
|
|
||||||
|
mockConn.On("Query", mock.Anything, mock.AnythingOfType("string"), testID, testUserID).Return(mockRows, nil).Once()
|
||||||
|
|
||||||
|
_, err := inventoryRepo.GetByID(context.Background(), testID, testUserID)
|
||||||
|
assert.Error(t, err)
|
||||||
|
mockConn.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user