package exampleservice import ( "context" "testing" "github.com/ditointernet/go-assert" "github.com/vingarcia/ksql" "github.com/vingarcia/ksql/ksqltest" "github.com/vingarcia/ksql/nullable" ) func TestCreateUserWithKsqlMock(t *testing.T) { t.Run("should call ksql.Insert correctly", func(t *testing.T) { var users []interface{} mockDB := ksql.Mock{ InsertFn: func(ctx context.Context, table ksql.Table, record interface{}) error { users = append(users, record) return nil }, } s := Service{ db: mockDB, streamChunkSize: 100, } user := UserEntity{Name: nullable.String("TestUser")} err := s.CreateUser(context.TODO(), user) assert.Equal(t, nil, err) assert.Equal(t, 1, len(users)) assert.Equal(t, &user, users[0]) }) t.Run("another way of testing input structs", func(t *testing.T) { var users []map[string]interface{} mockDB := ksql.Mock{ InsertFn: func(ctx context.Context, table ksql.Table, record interface{}) error { // The StructToMap function will convert a struct with `ksql` tags // into a map using the ksql attr names as keys. // // If you are inserting an anonymous struct (not usual) this function // can make your tests shorter: uMap, err := ksqltest.StructToMap(record) if err != nil { return err } users = append(users, uMap) return nil }, } s := Service{ db: mockDB, streamChunkSize: 100, } user := UserEntity{Name: nullable.String("TestUser")} err := s.CreateUser(context.TODO(), user) assert.Equal(t, nil, err) assert.Equal(t, 1, len(users)) assert.Equal(t, "TestUser", users[0]["name"]) }) } func TestUpdateUserScoreWithKsqlMock(t *testing.T) { t.Run("should call ksql.QueryOne() & Patch() correctly", func(t *testing.T) { var users []interface{} mockDB := ksql.Mock{ QueryOneFn: func(ctx context.Context, result interface{}, query string, params ...interface{}) error { // This function will use reflection to fill the // struct fields with the values from the map return ksqltest.FillStructWith(result, map[string]interface{}{ // Use int this map the keys you set on the ksql tags, e.g. `ksql:"score"` // Each of these fields represent the database rows returned // by the query. "score": 42, }) }, PatchFn: func(ctx context.Context, table ksql.Table, record interface{}) error { users = append(users, record) return nil }, } s := Service{ db: mockDB, streamChunkSize: 100, } err := s.UpdateUserScore(context.TODO(), 1, -2) assert.Equal(t, nil, err) assert.Equal(t, 1, len(users)) resultUser := UserEntity{ ID: 1, Score: nullable.Int(40), } assert.Equal(t, &resultUser, users[0]) }) } func TestListUsersWithKsqlMock(t *testing.T) { t.Run("should call ksql.QueryOne() & Query() correctly", func(t *testing.T) { mockDB := ksql.Mock{ QueryOneFn: func(ctx context.Context, result interface{}, query string, params ...interface{}) error { // This function will use reflection to fill the // struct fields with the values from the map return ksqltest.FillStructWith(result, map[string]interface{}{ // Use int this map the keys you set on the ksql tags, e.g. `ksql:"score"` // Each of these fields represent the database rows returned // by the query. "count": 420, }) }, QueryFn: func(ctx context.Context, results interface{}, query string, params ...interface{}) error { return ksqltest.FillSliceWith(results, []map[string]interface{}{ { "id": 1, "name": "fake name", "age": 42, }, { "id": 2, "name": "another fake name", "age": 43, }, }) }, } s := Service{ db: mockDB, streamChunkSize: 100, } total, users, err := s.ListUsers(context.TODO(), 40, 2) assert.Equal(t, nil, err) assert.Equal(t, 420, total) assert.Equal(t, 2, len(users)) expectedUsers := []UserEntity{ { ID: 1, Name: nullable.String("fake name"), Age: nullable.Int(42), }, { ID: 2, Name: nullable.String("another fake name"), Age: nullable.Int(43), }, } assert.Equal(t, expectedUsers, users) }) } func TestStreamAllUsersWithKsqlMock(t *testing.T) { t.Run("should call ksql.QueryChunks correctly", func(t *testing.T) { mockDB := ksql.Mock{ QueryChunksFn: func(ctx context.Context, parser ksql.ChunkParser) error { // Chunk 1: err := ksqltest.CallFunctionWithRows(parser.ForEachChunk, []map[string]interface{}{ { "id": 1, "name": "fake name", "age": 42, }, { "id": 2, "name": "another fake name", "age": 43, }, }) if err != nil { return err } // Chunk 2: err = ksqltest.CallFunctionWithRows(parser.ForEachChunk, []map[string]interface{}{ { "id": 3, "name": "yet another fake name", "age": 44, }, }) return err }, } s := Service{ db: mockDB, streamChunkSize: 2, } var users []UserEntity err := s.StreamAllUsers(context.TODO(), func(u UserEntity) error { users = append(users, u) return nil }) assert.Equal(t, nil, err) assert.Equal(t, 3, len(users)) expectedUsers := []UserEntity{ { ID: 1, Name: nullable.String("fake name"), Age: nullable.Int(42), }, { ID: 2, Name: nullable.String("another fake name"), Age: nullable.Int(43), }, { ID: 3, Name: nullable.String("yet another fake name"), Age: nullable.Int(44), }, } assert.Equal(t, expectedUsers, users) }) } func TestDeleteUserWithKsqlMock(t *testing.T) { t.Run("should call ksql.Delete correctly", func(t *testing.T) { var ids []interface{} mockDB := ksql.Mock{ DeleteFn: func(ctx context.Context, table ksql.Table, idOrObj interface{}) error { ids = append(ids, idOrObj) return nil }, } s := Service{ db: mockDB, streamChunkSize: 100, } err := s.DeleteUser(context.TODO(), 42) assert.Equal(t, nil, err) assert.Equal(t, 1, len(ids)) assert.Equal(t, 42, ids[0]) }) }