Testing Guide
Testing Guide
Section titled “Testing Guide”Testing practices for ION Flow - How to write and run tests.
Overview
Section titled “Overview”ION Flow uses Go’s built-in testing framework. All core actions require tests, and comprehensive testing is encouraged for services and controllers.
Running Tests
Section titled “Running Tests”All Tests
Section titled “All Tests”# From project rootgo test ./...
# With verbose outputgo test -v ./...
# With coveragego test -cover ./...
# Coverage reportgo test -coverprofile=coverage.out ./...go tool cover -html=coverage.outModule-Specific Tests
Section titled “Module-Specific Tests”# Core testscd core && go test ./...
# Backend testscd backend && go test ./...
# Package testscd packages/channel && go test ./...Single Test
Section titled “Single Test”go test -run TestFunctionName ./path/to/packageTest Structure
Section titled “Test Structure”Standard Test File
Section titled “Standard Test File”package mypackage
import ( "testing"
"github.com/stretchr/testify/assert")
func TestFunctionName_Scenario(t *testing.T) { // Arrange input := "test input" expected := "expected output"
// Act result := FunctionName(input)
// Assert assert.Equal(t, expected, result)}Table-Driven Tests
Section titled “Table-Driven Tests”func TestExecute(t *testing.T) { tests := []struct { name string input interface{} expected interface{} wantErr bool }{ { name: "valid input", input: map[string]any{"key": "value"}, expected: map[string]any{"result": "value"}, wantErr: false, }, { name: "invalid input", input: nil, expected: nil, wantErr: true, }, }
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := Execute(tt.input)
if tt.wantErr { assert.Error(t, err) return }
assert.NoError(t, err) assert.Equal(t, tt.expected, result) }) }}Testing Core Actions
Section titled “Testing Core Actions”Node Action Tests
Section titled “Node Action Tests”package condition
import ( "testing"
"gitlab.com/altacrest/flow_binaries/core/models" "gitlab.com/altacrest/flow_binaries/core/models/status")
func TestExecute_TrueCondition(t *testing.T) { node := models.Node{ ID: "test_node", Type: "condition", Data: []interface{}{ map[string]interface{}{ "field": "active", "operator": "is_equal", "value": "true", }, }, }
queue := models.Queue{ Data: map[string]any{"test": "data"}, }
outputs, message, sts := Execute(node, queue)
if sts != status.Success { t.Errorf("Expected success, got %s: %s", sts, message) }
if len(outputs) == 0 { t.Error("Expected outputs, got none") }
if *outputs[0].TargetHandle != "then" { t.Errorf("Expected 'then' output, got '%s'", *outputs[0].TargetHandle) }}
func TestExecute_FalseCondition(t *testing.T) { // Similar test for false branch}
func TestExecute_InvalidOperator(t *testing.T) { // Test error handling}Testing Services
Section titled “Testing Services”Service Tests with Database
Section titled “Service Tests with Database”package services
import ( "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require")
func TestGetCompanyFlow(t *testing.T) { // Setup test company company := &models.Company{ ID: 1, Schema: "test_schema", }
// Create test flow flow := &models.Flow{ ID: 1, Name: "Test Flow", }
// Test result, err := GetCompanyFlow(company, 1)
require.NoError(t, err) assert.Equal(t, flow.Name, result.Name)}Testing Controllers
Section titled “Testing Controllers”HTTP Handler Tests
Section titled “HTTP Handler Tests”package controllers
import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing"
"github.com/stretchr/testify/assert")
func TestFindCompanyFlow(t *testing.T) { // Create request req, err := http.NewRequest("GET", "/api/1.0/tenants/1/flows/1", nil) if err != nil { t.Fatal(err) }
// Create response recorder rr := httptest.NewRecorder()
// Create handler handler := http.HandlerFunc(FindCompanyFlow)
// Execute handler.ServeHTTP(rr, req)
// Assert assert.Equal(t, http.StatusOK, rr.Code)}
func TestNewCompanyFlow(t *testing.T) { body := map[string]any{ "name": "New Flow", "flow": map[string]any{ "nodes": []any{}, "edges": []any{}, }, }
jsonBody, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", "/api/1.0/tenants/1/flows", bytes.NewBuffer(jsonBody)) req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder() handler := http.HandlerFunc(NewCompanyFlow) handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusCreated, rr.Code)}Testing Helpers
Section titled “Testing Helpers”Helper Function Tests
Section titled “Helper Function Tests”package helpers
import ( "testing")
func TestParseStringWithDefault(t *testing.T) { tests := []struct { input string def string expected string }{ {"value", "default", "value"}, {"", "default", "default"}, {" ", "default", "default"}, }
for _, tt := range tests { result := ParseStringWithDefault(tt.input, tt.def) if result != tt.expected { t.Errorf("ParseStringWithDefault(%q, %q) = %q; want %q", tt.input, tt.def, result, tt.expected) } }}Test Utilities
Section titled “Test Utilities”testify/assert
Section titled “testify/assert”import "github.com/stretchr/testify/assert"
// Equalityassert.Equal(t, expected, actual)assert.NotEqual(t, unexpected, actual)
// Nil checksassert.Nil(t, value)assert.NotNil(t, value)
// Error checksassert.Error(t, err)assert.NoError(t, err)
// Booleanassert.True(t, condition)assert.False(t, condition)
// Containsassert.Contains(t, slice, element)testify/require
Section titled “testify/require”Same as assert but fails immediately:
import "github.com/stretchr/testify/require"
require.NoError(t, err) // Stops test if errorMocking
Section titled “Mocking”For complex dependencies, use interfaces and mocks:
// Interfacetype FlowService interface { GetFlow(id string) (*models.Flow, error)}
// Mocktype MockFlowService struct { GetFlowFunc func(id string) (*models.Flow, error)}
func (m *MockFlowService) GetFlow(id string) (*models.Flow, error) { return m.GetFlowFunc(id)}
// Usage in testfunc TestController(t *testing.T) { mock := &MockFlowService{ GetFlowFunc: func(id string) (*models.Flow, error) { return &models.Flow{ID: 1, Name: "Test"}, nil }, }
// Use mock in test}Test Coverage Requirements
Section titled “Test Coverage Requirements”| Module | Minimum Coverage |
|---|---|
| Core Actions | Required |
| Services | Recommended |
| Controllers | Optional |
| Helpers | Recommended |
Related Documentation
Section titled “Related Documentation”- Development Guide - Setup
- Building Guide - Build process