Testing

Testing strategy and framework for WvdS FPC RAD Studio.

Test Types

Type Scope Tools Execution
Unit Tests Individual functions FPCUnit Local
Integration Tests Component interaction FPCUnit Local
E2E Tests Entire extension VS Code Test Runner CI

Unit Tests

Structure

sources/
├── extensions/
│   └── wvds.vscode.build/
│       ├── pas/
│       │   ├── Build.Service.pas
│       │   └── Build.Models.pas
│       └── tests/
│           ├── Build.Service.Tests.pas
│           └── Build.Models.Tests.pas

Test Framework

unit Build.Service.Tests;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  TestFramework,
  Build.Service,
  Build.Models;
 
type
  TBuildServiceTest = class(TTestCase)
  published
    procedure TestValidatePath_ValidPath_ReturnsTrue;
    procedure TestValidatePath_InvalidPath_ReturnsFalse;
    procedure TestGenerateCommand_DebugMode_IncludesDebugFlags;
  end;
 
implementation
 
procedure TBuildServiceTest.TestValidatePath_ValidPath_ReturnsTrue;
var
  Error: string;
begin
  CheckTrue(ValidateBuildPath('%USERPROFILE%\Projects\MyApp', Error));
  CheckEquals('', Error);
end;
 
procedure TBuildServiceTest.TestValidatePath_InvalidPath_ReturnsFalse;
var
  Error: string;
begin
  CheckFalse(ValidateBuildPath('', Error));
  CheckNotEquals('', Error);
end;
 
procedure TBuildServiceTest.TestGenerateCommand_DebugMode_IncludesDebugFlags;
var
  Config: TWvdSBuildConfig;
  Command: string;
begin
  Config.Mode := bmDebug;
  Config.ProjectPath := 'test.lpr';
 
  Command := GenerateBuildCommand(Config);
 
  CheckTrue(Pos('-g', Command) > 0, 'Debug flag missing');
  CheckTrue(Pos('-O0', Command) > 0, 'No-optimization flag missing');
end;
 
initialization
  RegisterTest(TBuildServiceTest.Suite);
 
end.

Naming Conventions

Test{Feature}_{Scenario}_{ExpectedResult}

Examples:
TestValidatePath_ValidPath_ReturnsTrue
TestValidatePath_EmptyString_ReturnsFalse
TestGenerateCommand_ReleaseMode_IncludesOptimization

Ensuring Testability

Service Design

// TESTABLE - No UI dependency
function ValidateName(const AName: string; out AError: string): Boolean;
 
// NOT TESTABLE - UI in logic
procedure ValidateAndShowError(const AName: string);

Dependency Injection

// TESTABLE - Dependency injected
function ProcessFile(const APath: string; AFileReader: IFileReader): TResult;
 
// NOT TESTABLE - Hardcoded dependency
function ProcessFile(const APath: string): TResult;
begin
  Content := ReadFile(APath);  // Not mockable
end;

Mocking

type
  TMockFileReader = class(TInterfacedObject, IFileReader)
    FContent: string;
    function ReadFile(const APath: string): string;
  end;
 
function TMockFileReader.ReadFile(const APath: string): string;
begin
  Result := FContent;  // Predefined content
end;
 
procedure TProcessorTest.TestProcessFile_ValidContent_Succeeds;
var
  Mock: TMockFileReader;
  Processor: TProcessor;
begin
  Mock := TMockFileReader.Create;
  Mock.FContent := 'test content';
 
  Result := ProcessFile('any.txt', Mock);
 
  CheckEquals('expected output', Result);
end;

Integration Tests

unit Integration.BuildPipeline.Tests;
 
procedure TBuildPipelineTest.TestFullBuild_ConsoleApp_ProducesExe;
var
  Project: TWvdSProject;
  Result: TWvdSBuildResult;
begin
  // Setup
  Project := CreateTestProject(ptConsole);
 
  // Execute
  Result := BuildProject(Project);
 
  // Verify
  CheckEquals(bsSuccess, Result.Status);
  CheckTrue(FileExists(Result.OutputPath));
 
  // Cleanup
  DeleteTestProject(Project);
end;

E2E Tests

VS Code Extension Testing with @vscode/test-electron:

// test/extension.test.js (generated from Pascal)
const vscode = require('vscode');
const assert = require('assert');
 
suite('Extension Test Suite', () => {
  test('Build command exists', async () => {
    const commands = await vscode.commands.getCommands();
    assert.ok(commands.includes('wvds.build.run'));
  });
 
  test('Build command executes', async () => {
    await vscode.commands.executeCommand('wvds.build.run');
    // Verify output channel contains expected message
  });
});

Test Execution

Local

# Unit tests
wvds-test unit
 
# Integration tests
wvds-test integration
 
# All tests
wvds-test all

CI

test:
  runs-on: ubuntu-latest
  steps:
    - name: Run Unit Tests
      run: wvds-test unit --report junit

    - name: Run E2E Tests
      run: wvds-test e2e --report junit

    - name: Upload Results
      uses: actions/upload-artifact@v3
      with:
        name: test-results
        path: binaries/logs/test-*.xml

Code Coverage

wvds-test unit --coverage
 
# Generates:
# binaries/logs/coverage.html
# binaries/logs/coverage.json

Minimum Coverage:

  • Services: 80%
  • Models: 90%
  • Utilities: 70%

See also

Zuletzt geändert: on 2026/01/29 at 10:26 PM