- STACK.md - Technologies and dependencies (.NET 4.7.2, NuGet, Costura.Fody) - ARCHITECTURE.md - Layered CLI with ICncMachine factory pattern - STRUCTURE.md - Directory layout and where to add new code - CONVENTIONS.md - C# style, naming, result wrapper pattern - TESTING.md - NUnit 3 + Moq, stubs, ignored FOCAS tests - INTEGRATIONS.md - FOCAS, LSV2, FTP, RSA licensing - CONCERNS.md - Blocking async, silent catch, no logging, Windows-only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.8 KiB
Testing Patterns
Analysis Date: 2026-05-18
Test Framework
Runner:
- NUnit 3.13.3 —
NcProgramManager.Tests/packages.config - NUnit3TestAdapter 4.2.1 — VS/dotnet test runner integration
- Config:
NcProgramManager.Tests/nunit.runsettings
Assertion Library:
- NUnit fluent API:
Assert.That(actual, Is.True),Is.EqualTo(),Is.InstanceOf<T>()
Mocking:
- Moq 4.18.4 for interface mocking
- Castle.Core 5.1.1 (Moq dependency)
- Custom delegates for
refparameter workaround (Moq limitation with P/Invoke refs)- Example:
NcProgramManager.Tests/Unit/FanucMachineTests.cs
- Example:
Run Commands:
# Standard NUnit runner or VS Test Explorer
dotnet test NcProgramManager.Tests/NcProgramManager.Tests.csproj
# Or via Dockerfile:
docker build -f Dockerfile.test .
Test File Organization
Location:
- All tests in
NcProgramManager.Tests/(separate project) - Unit tests:
NcProgramManager.Tests/Unit/ - Integration tests:
NcProgramManager.Tests/Integration/ - Stubs:
NcProgramManager.Tests/Integration/Stubs/
Naming:
- Unit:
{Subject}Tests.cs—NcProgramValidatorTests.cs,FanucMachineTests.cs - Integration:
{Subject}IntegrationTests.cs—HeidenhainMachineIntegrationTests.cs - Stubs:
{Protocol}ServerStub.cs—FtpServerStub.cs,Lsv2ServerStub.cs
Test Structure
Fixture Pattern:
[TestFixture]
public class NcProgramValidatorTests
{
[SetUp]
public void SetUp() { ... }
[Test]
public void MethodName_Condition_ExpectedResult()
{
// arrange
// act
// assert (NUnit fluent)
}
}
Parameterized Tests:
[TestCase(CncManufacturer.Fanuc)]
[TestCase(CncManufacturer.Siemens)]
[TestCase(CncManufacturer.Heidenhain)]
[TestCase(CncManufacturer.Mitsubishi)]
public void Validate_TabCharacter_ReturnsWarning(CncManufacturer m) { ... }
Example: NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs
Async Tests:
- No
async Tasktest methods — use.GetAwaiter().GetResult()to block- Example:
NcProgramManager.Tests/Integration/HeidenhainMachineIntegrationTests.cs
- Example:
Test Categories:
[Category("Integration")] // marks integration tests
Mocking
Interface mocking via Moq:
var mockDialect = new Mock<IFocasDialect>();
mockDialect.Setup(d => d.Connect(...)).Returns(...);
var machine = new FanucMachine(config, mockDialect.Object);
Example: NcProgramManager.Tests/Unit/FanucMachineTests.cs
Reflection-based state injection (for bypassing protected fields):
// Set internal connection state without real hardware
typeof(FanucMachine)
.GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(machine, ConnectionState.Connected);
Example: NcProgramManager.Tests/Unit/FanucMachineTests.cs
What to mock:
- Protocol interfaces:
IFocasDialect,ILsv2Client,ISiemensFtpClient,IMitsubishiFtpClient - Licensing:
IMachineFingerprint,ILicenseValidator
In-Process Protocol Stubs
FtpServerStub (NcProgramManager.Tests/Integration/Stubs/FtpServerStub.cs):
- Minimal FTP server for Siemens/Mitsubishi integration testing
- In-memory file store:
Dictionary<string, string> Files - Supported commands: USER, PASS, CWD, TYPE, PASV, LIST, NLST, RETR, STOR, DELE
- Usage: Start before test, inject port into machine config
Lsv2ServerStub (NcProgramManager.Tests/Integration/Stubs/Lsv2ServerStub.cs):
- Minimal LSV2 TCP server for Heidenhain integration testing
- Implements LSV2 framing (STX, SIZE, CMD, data, CRC)
- Thread-per-client architecture
Ignored Tests
FOCAS DLL-dependent tests marked [Ignore]:
- All tests requiring actual
Fwlib32.dllcalls are ignored - Reason: Cannot mock static P/Invoke calls; DLL requires real Fanuc hardware on Windows
- Example:
NcProgramManager.Tests/Unit/FanucMachineTests.cs
Pattern for skipping:
[Test]
[Ignore("Requires Fanuc FOCAS DLL and real hardware")]
public void ConnectAsync_ValidConfig_Connects() { ... }
Coverage Approach
Well-covered:
NcProgramValidator— universal rules + all 4 manufacturers, 30+ test casesNcProgramManager.Tests/Unit/NcProgramValidatorTests.cs
FanucProgramparsing —FanucProgramParsingTests.csIsoProgramFormatter—IsoProgramFormatterTests.csCncMachineFactorydispatch —CncMachineFactoryTests.csLicenseValidator— 6 unit tests via internal ctor injection —LicenseValidatorTests.cs
Partially covered (blocked by hardware):
FanucMachineconnect/read/write — FOCAS tests[Ignore]d- Heidenhain/Siemens/Mitsubishi machines — integration tests use stubs
Not covered:
MachineFingerprint(WMI, Windows-only, no mocked tests)LicenseFileparsing edge casesProgram.csCLI orchestration (no CLI-level tests)
Testing analysis: 2026-05-18 Update when test framework or patterns change