Table of Contents

Test Block Design Philosophy

Test blocks are the cornerstone of the C# Reference Architecture, providing an abstraction layer that simplifies interaction with the IG-XL tester platform. This document outlines the fundamental philosophy behind test block design, particularly regarding parameter selection and the balance between usability and flexibility.

Core Design Principles

Abstraction Above IG-XL PublicAPI

Test blocks combine commonly used functionality by offering an abstraction model above the IG-XL PublicAPI layer. Rather than replacing the PublicAPI, test blocks complement and augment it by providing simplified interfaces for common test scenarios.

The goal is to make test code more:

  • Readable - Clear intent through intuitive naming and structure
  • Maintainable - Reduced code duplication and consistent patterns
  • Efficient - Pre-optimized implementations of common operations
  • Reusable - Generic implementations that work across multiple scenarios

The Usability-Flexibility Tradeoff

Test block design involves a fundamental tradeoff between usability and flexibility:

Too Much Generality

  • Results in excessive parameter lists
  • Creates a complicated use model
  • Increases implementation complexity
  • Makes the API harder to learn and use

Too Much Specificity

  • Forces the creation of many alternative implementations
  • Misses legitimate use cases
  • Requires users to handwrite more code
  • Reduces the value of the abstraction

Finding the Right Balance

The C#RA team strives to find the optimal balance by:

  1. Focus on Common Cases - Test blocks are designed to handle what would be the common case in most test scenarios
  2. Parameter Selection - Include parameters that cover 80-90% of typical use cases
  3. Accept Limitations - Acknowledge that not every edge case can or should be handled

Working with the IG-XL PublicAPI

Complementary, Not Exclusive

Test blocks and the IG-XL PublicAPI are designed to work together, not in opposition:

  • Use test blocks where they add value and simplify your code
  • Use PublicAPI directly where test blocks don't cover your specific needs
  • Mix both approaches freely within the same test method
Important

C#RA advocates against an "all or nothing" mandate. Users should never be forced into using only test blocks while forbidding direct PublicAPI calls. Both approaches have their place.

Example: Instrument-Specific Parameters

Consider the ClampVLo parameter in the ForceI test block. This parameter is specific to PPMU instruments and represents an uncommon configuration:

// Common case - using the test block
TheLib.Setup.Dc.ForceI(pins, forceCurrent, clampHiV);

// Uncommon case - using TheHdw for PPMU-specific features
TheHdw.PPMU.Pins(pins).ForceI(forceCurrent, clampHiV, clampLoV);

For the common case, the test block provides a clean, simple interface. For the uncommon PPMU-specific case where ClampVLo is needed, users can access TheHdw directly without penalty.

When to Use Each Approach

Use Test Blocks When... Use PublicAPI (TheHdw) When...
The functionality is commonly needed You need instrument-specific features
The test block covers your use case You need precise control over parameters
You want simpler, more readable code You're implementing an edge case
You benefit from the abstraction The test block doesn't support what you need

Extensibility and Customization

The C#RA extension model offers convenient customization when features are needed but not (yet) available in test blocks.

Extension Methods

Extension Methods allow users to add their own test blocks without modifying the C#RA codebase:

// In your test program project (not in C#RA)
public static class MyCustomExtensions {
    public static void CustomForceI(this ILib.ISetup.IDc dc, Pins pins, 
        double current, double clampHiV, double clampLoV) {
        // Your custom implementation with ClampVLo support
        TheHdw.PPMU.Pins(pins).ForceI(current, clampHiV, clampLoV);
    }
}

// Usage in your test method
using static Csra.Api;
...
TheLib.Setup.Dc.CustomForceI(pins, 1.0e-3, 3.3, 0.0);

Benefits of the Extension Model

  1. No Code Fork - Customizations live outside the C#RA codebase
  2. Easy Updates - Updating to a new C#RA version is not hindered
  3. Project-Specific - Each test program can have its own extensions
  4. Maintains Compatibility - Your code remains compatible with future C#RA releases

For more details, see Extensibility.

Feedback and Evolution

The C#RA Team Wants to Hear From You

The C#RA feature set is not static. The team actively:

  • Listens to gaps and needs that are not yet covered
  • Evaluates requests for common-case functionality
  • Integrates valuable feedback into the product
  • Embraces new requirements and added functionality

How to Provide Feedback

If you find yourself frequently needing a feature that isn't in test blocks:

  1. Report it - Create a feature request (see Request a Feature)
  2. Explain the use case - Help the team understand why it's common for your scenario
  3. Share your extension - Your custom implementation might inspire a better test block design

Continuous Improvement

The monthly release cycle allows for rapid integration of valuable features. If a parameter or capability proves to be more common than initially thought, it may be promoted into the standard test block interface.

Design Examples

Example 1: DC Force Simplification

The test block provides multiple overloads to support different use cases:

// Simple case - most common parameters only
TheLib.Setup.Dc.ForceV(pins, voltage);

// Moderate case - add clamp current
TheLib.Setup.Dc.ForceV(pins, voltage, clampCurrent);

// Complex case - add ranges
TheLib.Setup.Dc.ForceV(pins, voltage, clampCurrent, voltageRange, currentRange);

// Exceptional case - need DCVI-specific features
TheHdw.DCVI.Pins(pins).ForceV(voltage, clampCurrent, voltageRange, 
    currentRange, outputModeVoltage: true);

Example 2: Mixing Test Blocks and PublicAPI

Test methods commonly mix both approaches:

[TestMethod, Steppable, CustomValidation]
public void ParametricTest(PinList pinList, double voltage, string setup = "") {
    if (ShouldRunPreBody) {
        // Using test blocks for common operations
        TheLib.Setup.ApplyLevelsTiming();
        Services.Setup.Apply(setup);
        TheLib.Setup.Dc.Connect(pins);
        
        // Using PublicAPI for specific configuration
        if (needsSpecialConfig) {
            TheHdw.PPMU.Pins(ppmuPins).ClampVLo = specialValue;
        }
    }
    
    if (ShouldRunBody) {
        // Back to test blocks for measurement
        TheLib.Setup.Dc.ForceV(pins, voltage);
        _meas = TheLib.Acquire.Dc.Measure(pins);
    }
    
    if (ShouldRunPostBody) {
        TheLib.Setup.Dc.Disconnect(pins);
        TheLib.Datalog.TestParametric(_meas, voltage);
    }
}

Summary

The C# Reference Architecture test blocks are designed to:

  • ✅ Handle common test scenarios with simple, intuitive interfaces
  • ✅ Complement (not replace) the IG-XL PublicAPI
  • ✅ Allow easy divergence to PublicAPI for edge cases
  • ✅ Support extension for customer-specific needs
  • ✅ Evolve based on user feedback
  • ✅ Enable smooth upgrades through careful API design

By understanding this philosophy, you can make informed decisions about when to use test blocks, when to use the PublicAPI directly, and when to create your own extensions. The goal is to maximize your productivity while maintaining the flexibility to handle any test scenario your application requires.