Skip to content

Conversation

mitchdenny
Copy link
Member

@mitchdenny mitchdenny commented Apr 12, 2025

This PR includes significant changes to improve the testability of the CLI. Here is a summary of what is going on with this change:

  1. Moves code from InteractionUtils into a new service that we can inject into DI called InteractionService with an abstract interface that we can mock out if we need to.
  2. Moves some of the file-system scanning logic from AppHostHelper into a new IProjectLocator type which allows us to mock out some of the filesystem scanning logic in the future.
  3. Hoists the CertificateHelper logic into a CertificateService which allows us to override certificate handling behavior in tests.
  4. Introduces a INewCommandPrompter which captures some of the specific prompt operations for the NewCommand which has its happy path tested in this PR. The reason for having this additional interface is that it makes it easier to mock out just the specific operations that you want to intercept and have some specific automated fallbacks (e.g. selecting the first template, selecting the first template version, and accepting default project names and output paths). This interface has optional callbacks which can be populated to change the behavior on a per test basis.

The structure of a command test therefore looks something like this:

[Fact]
    public async Task NewCommandInteractiveFlowSmokeTest()
    {
        var services = CliTestHelper.CreateServiceCollection(options => {

            // Replace the default prompter with the test prompter which
            // automatically selects defaults - but can be overridden on
            // on a case by case basis.
            options.NewCommandPrompterFactory = (sp) =>
            {
                var interactionService = sp.GetRequiredService<IInteractionService>();
                return new TestNewCommandPrompter(interactionService);
            };

            // Replace the default CLI runner and mock out some responses
            // which drive the interactive UX (e.g. package search).
            options.DotNetCliRunnerFactory = (sp) =>
            {
                var runner = new TestDotNetCliRunner();
                runner.SearchPackagesAsyncCallback = (dir, query, prerelease, take, skip, nugetSource, cancellationToken) =>
                {
                    var package = new NuGetPackage()
                    {
                        Id = "Aspire.ProjectTemplates",
                        Source = "nuget",
                        Version = "9.2.0"
                    };

                    return (
                        0, // Exit code.
                        new NuGetPackage[] { package } // Single package.
                        );
                };

                return runner;
            };
        });
        var provider = services.BuildServiceProvider();

        var command = provider.GetRequiredService<NewCommand>();
        var result = command.Parse("new");

        var exitCode = await result.InvokeAsync().WaitAsync(CliTestConstants.DefaultTimeout);
        Assert.Equal(0, exitCode);
    }
}

@mitchdenny mitchdenny requested a review from davidfowl April 12, 2025 07:45
@mitchdenny mitchdenny self-assigned this Apr 12, 2025
@mitchdenny mitchdenny added this to the 9.3 milestone Apr 12, 2025
@mitchdenny mitchdenny closed this Apr 12, 2025
@mitchdenny mitchdenny reopened this Apr 12, 2025
@mitchdenny mitchdenny force-pushed the mitchdenny/moar-testing-goodness branch from e478f37 to db56345 Compare April 13, 2025 08:07
@mitchdenny mitchdenny merged commit 3865da9 into main Apr 13, 2025
174 checks passed
@mitchdenny mitchdenny deleted the mitchdenny/moar-testing-goodness branch April 13, 2025 10:22
@github-actions github-actions bot locked and limited conversation to collaborators May 14, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants