Documentation
¶
Overview ¶
Package testkit provides utilities for testing setups including a modular builder framework.
The testkit library offers a comprehensive set of tools for creating consistent, maintainable test environments. It provides interfaces, ready-to-use structs, and patterns for creating reusable builders, fixtures, and mocks.
Core Components ¶
The library is built around three main components:
1. Builder Interface and BaseBuilder: A flexible builder pattern implementation 2. BuilderFactory: Factory pattern for creating and managing different builder types 3. BuilderConfig: Configuration system for setting up builders with default values
Basic Usage ¶
Creating a simple builder:
builder := NewBaseBuilder()
builder.WithTag("env", "test").WithValidation(true)
result := builder.Build() // Returns nil for base builder
Using the factory pattern:
factory := NewBuilderFactory()
factory.Register("mybuilder", func() Builder {
return NewBaseBuilder()
})
builder, err := factory.Create("mybuilder")
if err != nil {
// handle error
}
Creating Custom Builders ¶
To create a custom builder, embed BaseBuilder and implement the Builder interface:
type MyObjectBuilder struct {
*BaseBuilder
obj *MyObject
}
func NewMyObjectBuilder() *MyObjectBuilder {
return &MyObjectBuilder{
BaseBuilder: NewBaseBuilder(),
obj: &MyObject{},
}
}
func (b *MyObjectBuilder) WithName(name string) *MyObjectBuilder {
if b.IsValidationEnabled() && name == "" {
b.AddError(errors.New("name cannot be empty"))
return b
}
b.obj.Name = name
return b
}
func (b *MyObjectBuilder) Build() interface{} {
if b.HasErrors() {
return fmt.Errorf("validation errors: %v", b.GetErrors())
}
// Return a copy to avoid mutation
return &MyObject{Name: b.obj.Name}
}
Configuration System ¶
Use BuilderConfig for setting up builders with defaults:
config := NewBuilderConfig()
config.WithValidation(false)
config.WithTag("env", "test")
config.WithDefault("name", "default_name")
builder := NewMyObjectBuilder()
config.ApplyTo(builder)
Thread Safety ¶
The builders in this library are not thread-safe by design. Each goroutine should use its own builder instance. Use Clone() to create independent copies when needed.
Error Handling ¶
Builders accumulate errors during configuration and report them at build time:
builder := NewMyObjectBuilder()
builder.WithName("") // Adds validation error
result := builder.Build()
if err, ok := result.(error); ok {
// Handle build errors
}
Index ¶
- Variables
- func RegisterBuilder(name string, createFunc func() Builder) error
- type BaseBuilder
- func (b *BaseBuilder) AddError(err error) *BaseBuilder
- func (b *BaseBuilder) Build() any
- func (b *BaseBuilder) ClearErrors() *BaseBuilder
- func (b *BaseBuilder) Clone() Builder
- func (b *BaseBuilder) GetErrors() []error
- func (b *BaseBuilder) GetTag(key string) string
- func (b *BaseBuilder) HasErrors() bool
- func (b *BaseBuilder) HasTag(key string) bool
- func (b *BaseBuilder) IsValidationEnabled() bool
- func (b *BaseBuilder) Reset() Builder
- func (b *BaseBuilder) WithTag(key, value string) *BaseBuilder
- func (b *BaseBuilder) WithValidation(enabled bool) *BaseBuilder
- type Builder
- type BuilderConfig
- type BuilderFactory
- type ConfigurableBuilder
- type TestUser
- type UserBuilder
- func (b *UserBuilder) ApplyConfig(config *BuilderConfig) error
- func (b *UserBuilder) Build() any
- func (b *UserBuilder) Clone() Builder
- func (b *UserBuilder) Reset() Builder
- func (b *UserBuilder) WithActive(active bool) *UserBuilder
- func (b *UserBuilder) WithAge(age int) *UserBuilder
- func (b *UserBuilder) WithEmail(email string) *UserBuilder
- func (b *UserBuilder) WithID(id int) *UserBuilder
- func (b *UserBuilder) WithMetadata(key string, value any) *UserBuilder
- func (b *UserBuilder) WithName(name string) *UserBuilder
- func (b *UserBuilder) WithUserTag(key, value string) *UserBuilder
Constants ¶
This section is empty.
Variables ¶
var DefaultFactory = NewBuilderFactory() //nolint:gochecknoglobals // intentional singleton for convenience API
DefaultFactory is a global factory instance for convenience.
Functions ¶
func RegisterBuilder ¶
RegisterBuilder registers a builder in the default factory.
Types ¶
type BaseBuilder ¶
type BaseBuilder struct {
// contains filtered or unexported fields
}
BaseBuilder provides common functionality for all builders. It implements the Builder interface and can be embedded in specific builders.
func NewBaseBuilder ¶
func NewBaseBuilder() *BaseBuilder
NewBaseBuilder creates a new BaseBuilder instance with default settings.
func (*BaseBuilder) AddError ¶
func (b *BaseBuilder) AddError(err error) *BaseBuilder
AddError adds an error to the builder's error collection.
func (*BaseBuilder) Build ¶
func (b *BaseBuilder) Build() any
Build is a default implementation that returns nil. Specific builders should override this method.
func (*BaseBuilder) ClearErrors ¶
func (b *BaseBuilder) ClearErrors() *BaseBuilder
ClearErrors removes all errors from the builder.
func (*BaseBuilder) Clone ¶
func (b *BaseBuilder) Clone() Builder
Clone creates a deep copy of the BaseBuilder.
func (*BaseBuilder) GetErrors ¶
func (b *BaseBuilder) GetErrors() []error
GetErrors returns all errors accumulated by the builder.
func (*BaseBuilder) GetTag ¶
func (b *BaseBuilder) GetTag(key string) string
GetTag retrieves a metadata tag value by key. Returns empty string if the tag doesn't exist.
func (*BaseBuilder) HasErrors ¶
func (b *BaseBuilder) HasErrors() bool
HasErrors returns true if the builder has any errors.
func (*BaseBuilder) HasTag ¶
func (b *BaseBuilder) HasTag(key string) bool
HasTag checks if a metadata tag exists.
func (*BaseBuilder) IsValidationEnabled ¶
func (b *BaseBuilder) IsValidationEnabled() bool
IsValidationEnabled returns whether validation is enabled for this builder.
func (*BaseBuilder) Reset ¶
func (b *BaseBuilder) Reset() Builder
Reset clears the builder state, allowing it to be reused.
func (*BaseBuilder) WithTag ¶
func (b *BaseBuilder) WithTag(key, value string) *BaseBuilder
WithTag adds a metadata tag to the builder. Tags can be used for identification, debugging, or conditional logic.
func (*BaseBuilder) WithValidation ¶
func (b *BaseBuilder) WithValidation(enabled bool) *BaseBuilder
WithValidation enables or disables validation for this builder.
type Builder ¶
type Builder interface {
// Build performs the final construction step and returns the built object.
// Implementations should return the appropriate type for their specific builder.
Build() any
// Reset clears the builder state, allowing it to be reused.
Reset() Builder
// Clone creates a deep copy of the builder with the same configuration.
Clone() Builder
}
Builder defines the interface that all builders must implement. This provides a common contract for all test builders in the library.
func CreateBuilder ¶
CreateBuilder creates a builder from the default factory.
type BuilderConfig ¶
type BuilderConfig struct {
ValidationEnabled bool
Tags map[string]string
DefaultValues map[string]any
}
BuilderConfig provides configuration options for builders.
func NewBuilderConfig ¶
func NewBuilderConfig() *BuilderConfig
NewBuilderConfig creates a new BuilderConfig with default settings.
func (*BuilderConfig) ApplyTo ¶
func (c *BuilderConfig) ApplyTo(builder Builder) error
ApplyTo applies the configuration to a builder.
func (*BuilderConfig) WithDefault ¶
func (c *BuilderConfig) WithDefault(key string, value any) *BuilderConfig
WithDefault sets a default value for a field.
func (*BuilderConfig) WithTag ¶
func (c *BuilderConfig) WithTag(key, value string) *BuilderConfig
WithTag adds a tag to the configuration.
func (*BuilderConfig) WithValidation ¶
func (c *BuilderConfig) WithValidation(enabled bool) *BuilderConfig
WithValidation sets the validation enabled flag.
type BuilderFactory ¶
type BuilderFactory struct {
// contains filtered or unexported fields
}
BuilderFactory provides a way to register and create different types of builders.
func NewBuilderFactory ¶
func NewBuilderFactory() *BuilderFactory
NewBuilderFactory creates a new BuilderFactory instance.
func (*BuilderFactory) Create ¶
func (f *BuilderFactory) Create(name string) (Builder, error)
Create creates a new builder instance by name.
func (*BuilderFactory) GetRegisteredNames ¶
func (f *BuilderFactory) GetRegisteredNames() []string
GetRegisteredNames returns all registered builder names.
func (*BuilderFactory) IsRegistered ¶
func (f *BuilderFactory) IsRegistered(name string) bool
IsRegistered checks if a builder is registered with the given name.
type ConfigurableBuilder ¶
type ConfigurableBuilder interface {
Builder
ApplyConfig(config *BuilderConfig) error
}
ConfigurableBuilder interface for builders that can accept configuration.
type TestUser ¶
type TestUser struct {
ID int
Name string
Email string
Age int
Active bool
Tags map[string]string
Metadata map[string]any
}
TestUser represents a test user entity for demonstration purposes.
type UserBuilder ¶
type UserBuilder struct {
*BaseBuilder
// contains filtered or unexported fields
}
UserBuilder builds TestUser instances for testing. It embeds BaseBuilder to inherit common functionality.
func NewUserBuilder ¶
func NewUserBuilder() *UserBuilder
NewUserBuilder creates a new UserBuilder instance.
func (*UserBuilder) ApplyConfig ¶
func (b *UserBuilder) ApplyConfig(config *BuilderConfig) error
ApplyConfig implements ConfigurableBuilder interface.
func (*UserBuilder) Build ¶
func (b *UserBuilder) Build() any
Build creates the TestUser instance. It performs final validation and returns the user or an error.
func (*UserBuilder) Clone ¶
func (b *UserBuilder) Clone() Builder
Clone creates a deep copy of the UserBuilder.
func (*UserBuilder) Reset ¶
func (b *UserBuilder) Reset() Builder
Reset clears the builder state for reuse.
func (*UserBuilder) WithActive ¶
func (b *UserBuilder) WithActive(active bool) *UserBuilder
WithActive sets the user active status.
func (*UserBuilder) WithAge ¶
func (b *UserBuilder) WithAge(age int) *UserBuilder
WithAge sets the user age.
func (*UserBuilder) WithEmail ¶
func (b *UserBuilder) WithEmail(email string) *UserBuilder
WithEmail sets the user email.
func (*UserBuilder) WithID ¶
func (b *UserBuilder) WithID(id int) *UserBuilder
WithID sets the user ID.
func (*UserBuilder) WithMetadata ¶
func (b *UserBuilder) WithMetadata(key string, value any) *UserBuilder
WithMetadata adds metadata to the user.
func (*UserBuilder) WithName ¶
func (b *UserBuilder) WithName(name string) *UserBuilder
WithName sets the user name.
func (*UserBuilder) WithUserTag ¶
func (b *UserBuilder) WithUserTag(key, value string) *UserBuilder
WithUserTag adds a tag specific to the user entity.