Skip to content

Conversation

Copy link

Copilot AI commented Dec 6, 2025

Purpose

Add XUnit test coverage for httpGetFunction and httpPostBodyFunction with test specification document for team review.

  • Implements 10 unit tests covering primary functionality and error handling
  • Creates test specification document (test-specification.md) following ASP.NET Core testing guidance
  • Test project uses XUnit, Moq, and follows Arrange-Act-Assert pattern

Does this introduce a breaking change?

[ ] Yes
[x] No

Pull Request Type

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Documentation content changes
[ ] Other... Please describe:

How to Test

  • Get the code
git clone https://github.com/Azure-Samples/functions-quickstart-dotnet-azd.git
cd functions-quickstart-dotnet-azd
git checkout copilot/add-unit-tests-http-functions
  • Test the code
dotnet build http.sln
dotnet test http.Tests/http.Tests.csproj

What to Check

Verify that the following are valid

  • All 10 tests pass (4 for httpGetFunction, 6 for HttpPostBody)
  • Test specification document covers required test cases and includes suggested additional tests
  • Tests properly mock ILogger dependencies using Moq
  • Tests validate both success paths and error handling (missing/invalid data)

Other Information

Test Coverage:

  • httpGetFunction: Name parameter handling (valid, empty, null) and logging
  • HttpPostBody: Valid person data, validation failures (empty/null name, zero age), and logging

Test Specification includes:

  • Testing methodology aligned with ASP.NET Core unit testing best practices
  • List of suggested additional tests (boundary cases, special characters, thread safety, security)
  • Notes on code quality observations (bitwise OR usage in validation)

The test specification document is ready for review by @fabiocav and team before potential iteration.

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:

  • learn.microsoft.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (dns block)

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

Original prompt

This section details on the original issue you should resolve

<issue_title>Unit tests needed</issue_title>
<issue_description>We need basic unit tests for the http functions shown here in the quickstart. Ensure at least the primary functionality of the httpget and httppost methods are covered, and any common error handling.

I want a spec to be written first in a .md file. I will review this with @fabiocav and team. Go ahead and attempt to implement it as well, but know that we will use the spec as source of truth, and make more iterations.

Other base requirements:

  • Assume XUnit
  • Make a list of suggested additional unit tests
  • Fetch this asp.net unit testing guidance and stay as close as possible to following the guidance
  • Run and validate the unit tests
    </issue_description>

<agent_instructions>Follow the instructions in the issue.</agent_instructions>

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.

Co-authored-by: paulyuk <1968137+paulyuk@users.noreply.github.com>
Copilot AI changed the title [WIP] Add unit tests for http functions with XUnit Add unit tests for HTTP trigger functions Dec 6, 2025
Copilot AI requested a review from paulyuk December 6, 2025 00:48
@paulyuk
Copy link
Contributor

paulyuk commented Dec 6, 2025

@copilot did you run and validate these unit tests? Can i see a report?

Copy link
Contributor

@paulyuk paulyuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please address my comments.

```

### Expected Outcomes
- All tests should pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected this PR to actually run and validate the tests, create a report, and ensure it matches expectations.

2. **Add Tests for New Features**: Any new functionality requires corresponding tests
3. **Refactor Tests**: When tests become complex, refactor to improve readability
4. **Review Coverage**: Regularly check code coverage and add tests for uncovered paths
5. **Document Complex Tests**: Add comments for non-obvious test scenarios
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per my last comment as a part of maintenance I want to run the tests. Should these be connected as a CI test Action in this repo?

@paulyuk paulyuk assigned Copilot and unassigned Copilot Dec 6, 2025
@paulyuk paulyuk requested a review from Copilot December 6, 2025 05:47
@paulyuk paulyuk marked this pull request as ready for review December 6, 2025 05:50
@paulyuk paulyuk requested review from Copilot and removed request for Copilot December 6, 2025 05:50
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive unit test coverage for two Azure Functions HTTP triggers (httpGetFunction and HttpPostBody) along with a detailed test specification document. The implementation follows XUnit and ASP.NET Core testing best practices, using Moq for dependency injection mocking and the Arrange-Act-Assert pattern throughout.

Key Changes:

  • Implements 10 unit tests covering both success and error scenarios for HTTP GET and POST functions
  • Creates a detailed test specification document aligned with ASP.NET Core unit testing guidance
  • Tests properly mock ILogger dependencies and verify both functional behavior and logging

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test-specification.md Comprehensive test specification documenting methodology, test cases, suggested additional tests, and best practices alignment
http.sln Adds test project to solution with Debug/Release configurations across Any CPU, x64, and x86 platforms
http.Tests/http.Tests.csproj Test project configuration with XUnit, Moq, and code coverage packages targeting .NET 8.0
http.Tests/httpGetFunctionTests.cs Four unit tests covering name parameter handling (valid, empty, null) and logging verification
http.Tests/HttpPostBodyTests.cs Six unit tests covering valid person data, validation failures (empty/null name, zero age), and logging

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version 2.3.0 of Microsoft.AspNetCore.Mvc.Core is quite old (released in 2018) and doesn't align with the .NET 8.0 target framework. For .NET 8.0 projects, consider using Microsoft.AspNetCore.Mvc.Core version 2.2.5 or relying on the framework reference already included in the main project. The main http.csproj includes <FrameworkReference Include="Microsoft.AspNetCore.App" /> which should provide the necessary types without requiring this separate package reference.

Suggested change
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +122
[Fact]
public void Run_LogsInformationMessage()
{
// Arrange
string name = "TestUser";

// Act
_function.Run(_mockRequest.Object, name);

// Assert
_mockLogger.Verify(
x => x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString()!.Contains("C# HTTP trigger function processed a request")),
null,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name Run_LogsInformationMessage is redundant with the other tests, which already verify logging behavior. This test doesn't add unique coverage since tests on lines 27-102 already verify that logging occurs with the appropriate messages. Consider removing this test or making it verify a specific logging scenario not covered by other tests (e.g., verify the exact log message format including "for Hello, TestUser.").

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +148
[Fact]
public void Run_WithValidPerson_LogsMultipleInformationMessages()
{
// Arrange
var person = new Person("Alice", 28);

// Act
_function.Run(_mockRequest.Object, person);

// Assert - Verify logger was called multiple times
_mockLogger.Verify(
x => x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
null,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Exactly(2));

// Verify first log contains URL info
_mockLogger.Verify(
x => x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString()!.Contains("processed a request for url")),
null,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);

// Verify second log contains person info
_mockLogger.Verify(
x => x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString()!.Contains("Alice") && v.ToString()!.Contains("28")),
null,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests Run_WithValidPerson_LogsMultipleInformationMessages and Run_WithValidPerson_ReturnsOkResultWithPersonalizedMessage are testing the same scenario (valid person). The logging verification in lines 111-148 duplicates the logging verification already done in lines 42-49. Consider consolidating these tests or removing the separate logging-focused test to reduce redundancy.

Copilot uses AI. Check for mistakes.
string expectedMessage = "Hello, World.";

// Act
var result = _function.Run(_mockRequest.Object, name!);
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The double null-forgiving operator usage (name! on line 86) is inconsistent with how null is handled in the actual function. The function signature accepts string name (non-nullable), but the implementation safely handles null values via string.IsNullOrEmpty(). Consider either changing the test to pass an empty string instead of null, or updating the actual function signature to string? name to better reflect the actual behavior being tested.

Suggested change
var result = _function.Run(_mockRequest.Object, name!);
var result = _function.Run(_mockRequest.Object, name);

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +80
[Fact]
public void Run_WithNullName_ReturnsBadRequest()
{
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null-forgiving operator null! is used to construct a Person with a null name. The Person record expects a non-nullable string but the actual function handles null values. This inconsistency between the record definition and runtime behavior should be documented in the test specification or the Person record should be updated to accept string? Name to match the actual validation logic.

Suggested change
[Fact]
public void Run_WithNullName_ReturnsBadRequest()
{
// NOTE: This test intentionally passes a null value for the Person's Name property,
// even though the Person record expects a non-nullable string. This highlights an
// inconsistency between the record definition and the actual validation logic.
// Ideally, the Person record should be updated to accept `string? Name` to match
// the function's handling of null values.
[Fact]
public void Run_WithNullName_ReturnsBadRequest()

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +43
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Debug|x64.ActiveCfg = Debug|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Debug|x64.Build.0 = Debug|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Debug|x86.ActiveCfg = Debug|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Debug|x86.Build.0 = Debug|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Release|Any CPU.Build.0 = Release|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Release|x64.ActiveCfg = Release|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Release|x64.Build.0 = Release|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Release|x86.ActiveCfg = Release|Any CPU
{32C6DAE7-2329-47AB-8551-2A9EF0353C9C}.Release|x86.Build.0 = Release|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Debug|x64.ActiveCfg = Debug|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Debug|x64.Build.0 = Debug|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Debug|x86.ActiveCfg = Debug|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Debug|x86.Build.0 = Debug|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Release|Any CPU.Build.0 = Release|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Release|x64.ActiveCfg = Release|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Release|x64.Build.0 = Release|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Release|x86.ActiveCfg = Release|Any CPU
{9A5C9145-5589-4C46-9418-9D0E3006F79F}.Release|x86.Build.0 = Release|Any CPU
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The addition of x64 and x86 platform configurations is inconsistent with the original solution which only had "Any CPU". Unless there's a specific requirement for platform-specific builds, consider keeping only "Any CPU" configuration to maintain simplicity. If these platforms are needed, ensure they're documented in the PR description or project documentation.

Copilot uses AI. Check for mistakes.
- Test thread safety (concurrent calls)

2. **httpPostBodyFunction**:
- Test with negative age value
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggested test for "negative age value" is valuable, but the current validation logic in HttpPostBody doesn't explicitly handle negative ages - it only checks for person.Age == 0. Consider adding this to the primary test cases rather than just suggested additional tests, as negative ages represent invalid data that should be rejected. The validation logic may need to be updated to person.Age <= 0 to properly handle this edge case.

Copilot uses AI. Check for mistakes.

## Notes

- The current implementation uses bitwise OR (`|`) instead of logical OR (`||`) in the validation condition. While this works, it's not idiomatic. Tests will verify current behavior, but this could be noted as a code quality improvement.
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test specification correctly identifies that the validation logic in HttpPostBody uses bitwise OR (|) instead of logical OR (||). However, there's a more significant issue: the condition string.IsNullOrEmpty(person.Age.ToString()) will never be true because int.ToString() always returns a non-empty string (e.g., "0" for zero). The check for person.Age == 0 handles the zero case, but this condition is redundant and misleading. Consider documenting this in the test specification or noting it as a code quality issue that tests are currently verifying.

Suggested change
- The current implementation uses bitwise OR (`|`) instead of logical OR (`||`) in the validation condition. While this works, it's not idiomatic. Tests will verify current behavior, but this could be noted as a code quality improvement.
- The current implementation uses bitwise OR (`|`) instead of logical OR (`||`) in the validation condition. While this works, it's not idiomatic. Tests will verify current behavior, but this could be noted as a code quality improvement.
- The validation logic also includes a redundant check: `string.IsNullOrEmpty(person.Age.ToString())`. Since `int.ToString()` never returns null or an empty string, this condition will always be false and is misleading. The check for `person.Age == 0` already handles the zero case. This should be documented as a code quality issue that tests are currently verifying.

Copilot uses AI. Check for mistakes.
Copilot AI added a commit that referenced this pull request Dec 6, 2025
- Cherry-picked unit tests from PR #21
- Ran all 10 tests successfully (100% pass rate)
- Created comprehensive test-report.md with detailed results
- Added GitHub Actions workflow for automatic test execution
- Updated .gitignore to exclude test artifacts

Co-authored-by: paulyuk <1968137+paulyuk@users.noreply.github.com>
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.

Unit tests needed

2 participants