agentsclimarketplace

Ioc test

Skill go-kid/ioc/skills/ioc-test

go-kid/ioc framework extension and testing guide. ALWAYS use this skill when the user asks about: extending IoC container, creating PostProcessors, custom tag processing, custom config loaders/binders, writing tests, testing IoC components, ioc.RunTest/RunErrorTest, slog integration, AOP/proxies, or advanced framework customization. Also use for questions like 'how to write tests for IoC', 'how to create custom tag', 'how to extend the container', 'how to add my own PostProcessor', 'how to test dependency injection', 'how to use slog with ioc', 'how to implement AOP', 'how to intercept component creation', 'how to customize property injection', or any go-kid/ioc testing, extension, and advanced customization questions. Triggers on: test, testing, ioc.RunTest, ioc.RunErrorTest, PostProcessor, ComponentPostProcessor, custom tag, extension, extend, customize, slog, logging, AOP, proxy, InstantiationAwareComponentPostProcessor, DefinitionRegistryPostProcessor, custom loader, custom binder.From its SKILL.md

Install
npx -y skills add go-kid/ioc --skill ioc-test

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.0 KB, as published. Nobody here has run it

go-kid/ioc Extension & Testing

Requires Go 1.21+.

Custom PostProcessors

PostProcessors are the primary extension mechanism. They can be registered in two ways:

  1. Via app.SetComponents (explicit)
  2. Via ioc.Register (any registered component implementing a PostProcessor interface is auto-discovered)

For detailed interface hierarchy and built-in processor patterns, see references/postprocessor-patterns.md.

Basic: ComponentPostProcessor

Intercept component initialization:

type MyProcessor struct{}

func (p *MyProcessor) PostProcessBeforeInitialization(component any, componentName string) (any, error) {
    if svc, ok := component.(*MyService); ok {
        svc.Instrumented = true
    }
    return component, nil
}

func (p *MyProcessor) PostProcessAfterInitialization(component any, componentName string) (any, error) {
    return component, nil
}

Advanced: InstantiationAwareComponentPostProcessor

Intercept property injection. Embed DefaultInstantiationAwareComponentPostProcessor and override only what you need:

import (
    "github.com/go-kid/ioc/component_definition"
    "github.com/go-kid/ioc/container/processors"
)

type MyInjector struct {
    processors.DefaultInstantiationAwareComponentPostProcessor
}

func (m *MyInjector) Order() int { return 100 }

func (m *MyInjector) PostProcessAfterInstantiation(component any, name string) (bool, error) {
    return true, nil  // true = continue processing properties
}

func (m *MyInjector) PostProcessProperties(
    properties []*component_definition.Property,
    component any, name string,
) ([]*component_definition.Property, error) {
    for _, p := range properties {
        if p.Tag == "my-tag" {
            // set value via reflection: p.Value.Set(reflect.ValueOf(...))
            p.SetArg(component_definition.ArgRequired, "false")
        }
    }
    return nil, nil
}

Custom Tag Scanning: DefinitionRegistryPostProcessor

Use DefaultTagScanDefinitionRegistryPostProcessor to register a custom struct tag:

type myTagScanner struct {
    processors.DefaultTagScanDefinitionRegistryPostProcessor
}

// Register:
app.SetComponents(
    &myTagScanner{
        processors.DefaultTagScanDefinitionRegistryPostProcessor{
            NodeType: "custom",    // property type identifier
            Tag:      "my-tag",    // struct tag to scan
        },
    },
    &MyInjector{},  // pair with a processor that handles "my-tag"
)

Factory Access: ComponentFactoryPostProcessor

func (p *MyProcessor) PostProcessComponentFactory(factory container.Factory) error {
    registry := factory.GetDefinitionRegistry()
    configure := factory.GetConfigure()
    return nil
}

Auto-Discovery

Any component registered via ioc.Register that implements ComponentPostProcessor or DefinitionRegistryPostProcessor is automatically picked up during PrepareComponents(). No special registration is needed beyond the standard ioc.Register.

Custom Loader

Implement configure.Loader to add a new config source:

type EnvLoader struct{}

func (l *EnvLoader) LoadConfig() ([]byte, error) {
    // return YAML/JSON bytes from any source
    return yaml.Marshal(map[string]string{"env": os.Getenv("APP_ENV")})
}

// Optionally implement definition.Ordered for load priority
func (l *EnvLoader) Order() int { return 10 }

Register: app.AddConfigLoader(&EnvLoader{})

Logging

log/slog Adapter

The framework provides an adapter to bridge syslog.Logger with Go 1.21's log/slog:

import "github.com/go-kid/ioc/syslog"

adapter := syslog.NewSlogAdapter(slogHandler)
ioc.Run(app.SetLogger(adapter))

Testing

Import: github.com/go-kid/ioc

ioc.RunTest

Start the IoC container and assert no error:

func TestMyComponent(t *testing.T) {
    comp := &MyComponent{}
    ioc.RunTest(t, app.SetComponents(comp))
    assert.Equal(t, "expected", comp.Value)
}

ioc.RunErrorTest

Expect the container to return an error:

func TestMissingDependency(t *testing.T) {
    comp := &struct {
        Svc *NonExistent `wire:""`
    }{}
    ioc.RunErrorTest(t, app.SetComponents(comp))
}

Common Test Patterns

// With config
ioc.RunTest(t,
    app.SetComponents(comp),
    app.SetConfigLoader(loader.NewRawLoader([]byte(`key: value`))),
)

// With log level
ioc.RunTest(t, app.LogTrace, app.SetComponents(comp))

// Test lifecycle: Close
a := ioc.RunTest(t, app.SetComponents(comp))
a.Close()
assert.True(t, comp.Closed)

// Access config after startup
a := ioc.RunTest(t, app.SetConfigLoader(loader.NewRawLoader(cfg)))
val := a.Get("some.key")

// Test with context
ctx := context.Background()
a, err := ioc.RunWithContext(ctx, app.SetComponents(comp))
assert.NoError(t, err)

// Test constructor injection
ioc.RunTest(t, app.SetComponents(NewService, &Repository{}))

// Test type-safe registration
ioc.Provide[Service](NewService)
ioc.RunTest(t, app.SetComponents(&Repository{}))

Test Organization

Follow existing project conventions:

unittest/
├── component/
│   ├── builtin_inject/          # wire tag: pointer, interface, slice, name
│   ├── constructor_inject/      # constructor injection
│   ├── embed_inject/            # embedded struct injection
│   ├── func_inject/             # func tag injection
│   ├── life_cycle_test/         # Init, Run, Close lifecycle
│   ├── modified_inject/         # custom PostProcessor injection
│   ├── post_processor/          # PostProcessor behavior
│   ├── refactor_test/           # refactored features and backward compatibility
│   └── special_inject_condition/ # qualifier, primary, required=false
└── configure/
    ├── configuration_test.go     # prefix tag, Binder
    ├── config_quote_test.go      # ${...} placeholders
    ├── expression_tag_test.go    # #{...} expressions
    ├── value_tag_test.go         # value tag types
    └── validate_test.go          # validation

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.