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:
- Focus on Common Cases - Test blocks are designed to handle what would be the common case in most test scenarios
- Parameter Selection - Include parameters that cover 80-90% of typical use cases
- 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
- No Code Fork - Customizations live outside the C#RA codebase
- Easy Updates - Updating to a new C#RA version is not hindered
- Project-Specific - Each test program can have its own extensions
- 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:
- Report it - Create a feature request (see Request a Feature)
- Explain the use case - Help the team understand why it's common for your scenario
- 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.
Related Topics
- Test Blocks - Detailed technical documentation
- Extensibility - How to create custom extensions
- Test Methods - Using test blocks in test methods
- Instrument Specific Features - When and how to use instrument-specific parameters
- Request a Feature - How to provide feedback