Live demo — data resets daily at 03:00 UTC. Nothing you enter is saved. Server UI →

product: maestro audience: test-developer authority: normative

Local Debugging with MSTest

Running test code locally with MSTest is the standard workflow — write and debug C# measurement functions before deploying to the real system.

Disable parallelization (MANDATORY)

The MSTest project template enables method-level parallelization by default. For hardware tests this IS dangerous — multiple tests execute simultaneously, causing concurrent PowerOn, Connect, and PowerOff calls against the same board.

Add this to a dedicated MSTestSettings.cs file in the test project:

[assembly: DoNotParallelize]

MUST NOT be inlined in the test class. MUST be in a separate MSTestSettings.cs file.

Without this, you will see intermittent hardware failures caused by concurrent test methods accessing the same instruments simultaneously.

Mapping YAML concepts to MSTest

YAML concept MSTest equivalent Notes
setup: steps [ClassInitialize] Runs once before all tests in the class
teardown: + run_on_abort: true [ClassCleanup] Runs once after all tests, even on failure
Each steps: entry [TestMethod] One test method per measurement step
measurement: limits Assert calls Use the same limit values as YAML
variables: block const or static fields Shared constants across test methods

MUST NOT use [TestInitialize] / [TestCleanup] for hardware setup/teardown — these run around each individual test method, causing repeated power cycles between every step.

Supplying system-injected parameters locally

In a live run, values like serial number and station config are injected by the system. Declare them as constants at the top of the test class with comments showing their system source:

[TestClass]
public sealed class FunctionalTestsTests
{
    // -------------------------------------------------------------------------
    // Local settings — values the system injects at runtime.
    // Change these to match your local development setup.
    // -------------------------------------------------------------------------
    private const string AgentHost       = "http://agent64.local:5000"; // cfg.AGENT_HOST
    private const string ProductId       = "ESH10000121";               // exec.tag.ProductId
    private const string ProductRevision = "1";                         // exec.tag.ProductRevision
    private const string SerialNumber    = "DEV-001";                   // exec.serial_number

    [ClassInitialize]
    public static void Setup(TestContext _)
    {
        FunctionalTests.Connect(AgentHost);
        FunctionalTests.LoadModule();
    }

    [ClassCleanup]
    public static void Teardown()
    {
        FunctionalTests.Disconnect();
    }

    [TestMethod]
    public void TestProgramDevice()
    {
        FunctionalTests.ProgramDevice(ProductId, ProductRevision, SerialNumber);
    }
}

Use a recognisable dev serial number (e.g. DEV-001) so that results accidentally recorded against a real system are easy to identify and discard.

MUST NOT scatter magic strings through individual test methods.

Full example

using Microsoft.VisualStudio.TestTools.UnitTesting;

[assembly: DoNotParallelize]

namespace MyTests;

[TestClass]
public class FunctionalTests
{
    private const string AgentHost = "http://agent64.local:5000"; // cfg.AGENT_HOST
    private const string Rail      = "3V3";
    private const double LowLimit  = 3.135;
    private const double HighLimit = 3.465;

    private static HardwareDriver _hw = null!;

    [ClassInitialize]
    public static void Setup(TestContext _)
    {
        _hw = new HardwareDriver(AgentHost);
        _hw.PowerOn();
        _hw.Connect();
    }

    [ClassCleanup]
    public static void Teardown()
    {
        _hw?.PowerOff();
        _hw?.Dispose();
    }

    [TestMethod]
    public void Measure_3V3_Rail()
    {
        double voltage = _hw.ReadRail(Rail);
        Assert.IsTrue(voltage >= LowLimit && voltage <= HighLimit,
            $"RAIL_3V3: {voltage} V outside [{LowLimit}, {HighLimit}]");
    }
}
An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.