Skip to content

Add interface-based architecture for DotNet static classes #2

Description

@StevenTCramer

Feature Request: Interface-Based Architecture for Static Classes

Problem

Currently, the DotNet static partial class and other command classes are not easily testable or mockable in unit tests. The static nature makes dependency injection and testing scenarios challenging.

Proposed Solution

Expose static classes like public static partial class DotNet as interfaces with the current static implementations serving as default implementations.

Current Architecture

  • DotNet uses static partial class pattern across 20+ files
  • Each method returns fluent builders (e.g., DotNetRunBuilder)
  • Builders call static CommandExtensions.Run() method
  • No dependency injection support

Proposed Interface Design

public interface IDotNet
{
  DotNetRunBuilder Run();
  DotNetBuildBuilder Build();
  DotNetBuildBuilder Build(string project);
  // ... all other command methods
}

public interface ICommandRunner
{
  CommandResult Run(string executable, params string[] arguments);
  CommandResult Run(string executable, string[] arguments, CommandOptions options);
}

public class DotNetService : IDotNet
{
  public DotNetRunBuilder Run() => DotNet.Run();
  public DotNetBuildBuilder Build() => DotNet.Build();
  // Delegates to existing static methods
}

Implementation Requirements

  1. Backward Compatibility: Zero breaking changes to existing API
  2. Builder Integration: Update builders to use injected ICommandRunner
  3. DI Support: Extension methods for IServiceCollection registration
  4. Testing: Enable full mockability for unit tests

Benefits

  • Testability: Mock CLI operations in unit tests
  • Dependency Injection: First-class DI container support
  • Custom Implementations: Environment-specific behavior (local vs CI)
  • Maintainability: Cleaner separation of concerns

Usage Examples

// Static approach (unchanged)
await DotNet.Build().WithConfiguration("Release").GetStringAsync();

// Interface-based approach (new)
await dotNetService.Build().WithConfiguration("Release").GetStringAsync();

// Testing with mocks
var mockRunner = new Mock<ICommandRunner>();
var dotNetService = new DotNetService(mockRunner.Object);

Implementation Plan

  1. Create core interfaces (IDotNet, ICommandRunner)
  2. Create default implementations wrapping existing statics
  3. Update builder classes for dependency injection
  4. Add DI registration extensions
  5. Comprehensive testing with mocked implementations

This would enable both usage patterns while maintaining full backward compatibility.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions