Skip to content

Comments

Improve GitHubRepoConnector testability via virtual factory method#90

Merged
Malcolmnixon merged 11 commits intomainfrom
copilot/improve-github-repo-connector-testing
Feb 17, 2026
Merged

Improve GitHubRepoConnector testability via virtual factory method#90
Malcolmnixon merged 11 commits intomainfrom
copilot/improve-github-repo-connector-testing

Conversation

Copy link
Contributor

Copilot AI commented Feb 17, 2026

Pull Request

Description

GitHubRepoConnector directly instantiates GitHubGraphQLClient, preventing comprehensive testing without live API calls. This change introduces a virtual factory method for GraphQL client creation, enabling test classes to inject mock HttpClient instances with pre-configured responses.

Changes

  • Virtual factory method: Added internal virtual GitHubGraphQLClient CreateGraphQLClient(string token) to GitHubRepoConnector
  • Optimized GraphQL client usage: Fixed CollectChangesFromPullRequestsAsync to receive the existing graphqlClient as the first parameter instead of creating a duplicate instance, eliminating redundant instantiation
  • Mock helper with structured data types: Created MockGitHubGraphQLHttpMessageHandler with helper methods that accept strongly-typed records for comprehensive testing:
    • AddCommitsResponse(IEnumerable<string>) - supports multiple commits
    • AddReleasesResponse(IEnumerable<MockRelease>) - supports multiple releases with strongly-typed MockRelease records (TagName, PublishedAt)
    • AddTagsResponse(IEnumerable<MockTag>) - supports multiple tags with strongly-typed MockTag records (Name, TargetOid)
    • AddPullRequestsResponse(IEnumerable<MockPullRequest>) - accepts PR data with full structure (Number, Title, Url, Merged, MergeCommitSha, HeadRefOid, Labels)
    • AddIssuesResponse(IEnumerable<MockIssue>) - accepts issue data with full structure (Number, Title, Url, State, Labels)
  • Strongly-typed mock data structures: Created organized mock records (MockCommit, MockRelease, MockTag, MockPullRequest, MockIssue) at the top of the file for better code organization and type safety
  • Reusable test infrastructure: Created internal MockableGitHubRepoConnector helper class for consistent mocking across test files
  • Comprehensive test coverage: Added 9 tests including:
    • Real integration tests that exercise GetBuildInformationAsync with fully mocked data
    • Tests validating version selection and changelog link generation
    • Tests verifying PR categorization into bugs vs changes based on labels
    • Tests confirming known issues identification from open issues
    • Dedicated tests for the mock handler functionality
  • Documentation: Added mocking patterns section to CONTRIBUTING.md with examples of helper method usage

Example Usage

// Derive from GitHubRepoConnector for testing
class TestableConnector : GitHubRepoConnector
{
    private readonly HttpClient _mockHttpClient;
    
    internal override GitHubGraphQLClient CreateGraphQLClient(string token)
        => new GitHubGraphQLClient(_mockHttpClient);
}

// Configure mock responses using strongly-typed helper methods
var mockHandler = new MockGitHubGraphQLHttpMessageHandler()
    .AddCommitsResponse(new[] { "commit123", "commit456" })
    .AddReleasesResponse(new[] { new MockRelease("v1.0.0", "2024-01-01T00:00:00Z") })
    .AddTagsResponse(new[] { new MockTag("v1.0.0", "commit123") })
    .AddPullRequestsResponse(new[]
    {
        new MockPullRequest(
            Number: 100,
            Title: "Fix bug",
            Url: "https://github.com/test/repo/pull/100",
            Merged: true,
            MergeCommitSha: "commit456",
            HeadRefOid: "bugfix-branch",
            Labels: new List<string> { "bug" })
    });

var connector = new TestableConnector(new HttpClient(mockHandler));
var buildInfo = await connector.GetBuildInformationAsync(version);

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code quality improvement

Related Issues

Addresses feature request to improve GitHubRepoConnector testing capabilities.

Pre-Submission Checklist

Before submitting this pull request, ensure you have completed the following:

Build and Test

  • Code builds successfully: dotnet build --configuration Release
  • All tests pass: dotnet test --configuration Release
  • Code produces zero warnings

Code Quality

  • Code formatting is correct: dotnet format --verify-no-changes
  • New code has appropriate XML documentation comments
  • Static analyzer warnings have been addressed

Quality Checks

Please run the following checks before submitting:

  • Spell checker passes: cspell "**/*.{md,cs}"
  • Markdown linter passes: markdownlint "**/*.md"
  • YAML linter passes: yamllint '**/*.{yml,yaml}'

Testing

  • Added unit tests for new functionality
  • Updated existing tests if behavior changed
  • All tests follow the AAA (Arrange, Act, Assert) pattern
  • Test coverage is maintained or improved

Documentation

  • Updated README.md (if applicable)
  • Updated ARCHITECTURE.md (if applicable)
  • Added code examples for new features (if applicable)
  • Updated requirements.yaml (if applicable)

Additional Notes

All changes are internal and non-breaking. The virtual method approach allows testing without exposing internals via InternalsVisibleTo pattern already in use. Test suite expanded from 170 to 179 tests, all passing across .NET 8/9/10.

The mock helper class significantly reduces boilerplate in tests by providing strongly-typed record structures (MockCommit, MockRelease, MockTag, MockPullRequest, MockIssue) for comprehensive GitHub GraphQL response mocking. These data structures are organized at the top of the file for better code organization and include all necessary fields to properly simulate real GitHub API responses, enabling tests to validate complex scenarios like version selection, PR categorization (bugs vs changes), and known issues identification. The MockableGitHubRepoConnector is now available as an internal reusable helper for any test that needs to mock GitHubRepoConnector behavior. Tests are properly organized with dedicated test files for the mock handler and comprehensive integration tests in the main GitHubRepoConnectorTests file.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature]: Improve GitHubRepoConnector Testing</issue_title>
<issue_description>### Problem Statement

Modify the GitHubRepoConnector to support better testing.

Proposed Solution

It should be possible to significantly improve the testing of the GitHubRepoConnector by being able to have testing code provide it an HttpClient pre-loaded with GraphQL responses for its GitHubGraphQLClient.

One approach may be to move the new GitHubGraphQLClient(token) to a virtual function (say CreateGraphQLClient). That way testing can be done by deriving from GitHubRepoConnector and overriding the RunCommandAsync and CreateGraphQLClient methods.

That would allow the derived class to totally control git/gh command execution so GitHubRepoConnector gets fed mock data about the repo and token, and then the drived class can construct a GitHubGraphQLClient with an HttpClient pre-loaded with mock data about the repo.

This would allow completely testing the GitHubRepoConnectors GetBuildInformationAsync method.

One thing to consider is if a helper class should be created that can better mock the HttpClient message handling. That way many tests could in theory use this same helper to create convincing GitHub GraphQL response data for tests.

Alternatives Considered

No response

Usage Examples

Benefits

Improved testing and code coverage.

Priority

Medium - Would improve my workflow

Willingness to Contribute

Yes, I can submit a pull request

Additional Context

No response

Checklist

  • I have searched existing issues to ensure this is not a duplicate
  • I have provided a clear description of the feature
  • I have explained why this feature would be useful</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits February 17, 2026 16:24
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve testing for GitHubRepoConnector Improve GitHubRepoConnector testability via virtual factory method Feb 17, 2026
Copilot AI requested a review from Malcolmnixon February 17, 2026 16:30
Copilot AI and others added 3 commits February 17, 2026 16:33
…ctChangesFromPullRequestsAsync

Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/testhost.dll --port 35449 --endpoint 127.0.0.1:035449 --role client --parentprocessid 4240 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/testhost.dll --port 37933 --endpoint 127.0.0.1:037933 --role client --parentprocessid 4233 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/testhost.dll --port 38931 --endpoint 127.0.0.1:038931 --role client --parentprocessid 4226 --telemetryoptedin false (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI and others added 2 commits February 17, 2026 16:48
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
…arate test files

Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/testhost.dll --port 36071 --endpoint 127.0.0.1:036071 --role client --parentprocessid 4125 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/testhost.dll --port 40181 --endpoint 127.0.0.1:040181 --role client --parentprocessid 4116 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/testhost.dll --port 43923 --endpoint 127.0.0.1:043923 --role client --parentprocessid 4108 --telemetryoptedin false (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI and others added 2 commits February 17, 2026 17:05
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
…wn issues

Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/testhost.dll --port 41069 --endpoint 127.0.0.1:041069 --role client --parentprocessid 4155 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/testhost.dll --port 43589 --endpoint 127.0.0.1:043589 --role client --parentprocessid 4139 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/testhost.dll --port 37333 --endpoint 127.0.0.1:037333 --role client --parentprocessid 4146 --telemetryoptedin false (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net10.0/testhost.dll --port 33663 --endpoint 127.0.0.1:033663 --role client --parentprocessid 4167 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net8.0/testhost.dll --port 35383 --endpoint 127.0.0.1:035383 --role client --parentprocessid 4158 --telemetryoptedin false (http block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/DemaConsulting.BuildMark.Tests.deps.json /home/REDACTED/work/BuildMark/BuildMark/test/DemaConsulting.BuildMark.Tests/bin/Release/net9.0/testhost.dll --port 42579 --endpoint 127.0.0.1:042579 --role client --parentprocessid 4151 --telemetryoptedin false (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@Malcolmnixon Malcolmnixon marked this pull request as ready for review February 17, 2026 17:37
@Malcolmnixon Malcolmnixon merged commit 2c9e388 into main Feb 17, 2026
11 checks passed
@Malcolmnixon Malcolmnixon deleted the copilot/improve-github-repo-connector-testing branch February 17, 2026 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Improve GitHubRepoConnector Testing

2 participants