What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To test FizzBuzz in ASP.NET Core, put the rule in a plain C# method, cover it with xUnit unit tests, and add one integration test that calls the HTTP endpoint through WebApplicationFactory<Program>. The arithmetic cases belong in the unit tests. The integration test only needs to prove that the route is wired up and returns the right text.

Start with the rule contract

FizzBuzz is application logic. ASP.NET Core only matters once that logic is exposed over HTTP. Before writing any test, fix the input and output rules, because the tests check the contract, not the framework.

The conventional rules are: multiples of 3 return Fizz, multiples of 5 return Buzz, multiples of both 3 and 15 return FizzBuzz, and every other number returns itself as text. ASP.NET Core does not impose these rules. A tutorial chooses them, and the choice should be stated in the article and in the test names.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Input Expected output Reason
1 “1” Not divisible by 3 or 5
3 “Fizz” Divisible by 3 only
5 “Buzz” Divisible by 5 only
15 “FizzBuzz” Divisible by both 3 and 5
0 “FizzBuzz” Zero is divisible by every integer, so the code below returns this value. A stricter contract may reject it instead.
-3 “Fizz” The modulo check treats negative multiples the same way. Valid only if your contract accepts negatives.

Zero and negative numbers are contract decisions, not framework requirements. If your application should reject them, throw ArgumentOutOfRangeException inside the method and add a test that uses Assert.Throws. A widely read xUnit walkthrough with the same title checks the output for 1 to 100. That is a choice made by that example. Your application does not need to produce exactly 100 values.

Set up the projects

The steps below target .NET 10 and ASP.NET Core 10.0. Microsoft’s current integration-testing guidance, titled “Integration tests in ASP.NET Core,” is written for ASP.NET Core 10.0. If you target another version, check the matching documentation before copying package versions.

  1. Create the web application with the empty web template: dotnet new web -n FizzBuzzApi -f net10.0
  2. Create the xUnit test project: dotnet new xunit -n FizzBuzzApi.Tests -f net10.0
  3. Reference the web project from the test project: cd FizzBuzzApi.Tests, then dotnet add reference ../FizzBuzzApi/FizzBuzzApi.csproj
  4. Add the integration-test package: dotnet add package Microsoft.AspNetCore.Mvc.Testing --version 10.0.*. Use the 10.0 line so it matches the framework your app targets.

The xUnit template already supplies the test runner and the Microsoft test SDK. The Microsoft.AspNetCore.Mvc.Testing package supplies the test web host and the in-memory test server that WebApplicationFactory uses.

Write the FizzBuzz logic as a plain method

Keep the rule in a static class with no ASP.NET Core types. This lets the unit tests run without starting a web host.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
using System.Globalization;

namespace FizzBuzzApi;

public static class FizzBuzz
{
    public static string Evaluate(int number)
    {
        if (number % 15 == 0) return "FizzBuzz";
        if (number % 3 == 0) return "Fizz";
        if (number % 5 == 0) return "Buzz";
        return number.ToString(CultureInfo.InvariantCulture);
    }
}

The check for 15 comes first. If the 3 check ran first, 15 would return Fizz and never reach FizzBuzz. This ordering is the most common bug in FizzBuzz code, so one of the unit tests below targets it directly.

Unit tests for the rule

Microsoft’s integration-testing guidance recommends unit tests for routine method logic, and FizzBuzz is exactly that. Put these tests in FizzBuzzTests.cs in the test project:

using FizzBuzzApi;
using Xunit;

public class FizzBuzzTests
{
    [Theory]
    [InlineData(1, "1")]
    [InlineData(2, "2")]
    [InlineData(7, "7")]
    public void ReturnsTheNumberWhenNotDivisibleByThreeOrFive(int input, string expected)
    {
        Assert.Equal(expected, FizzBuzz.Evaluate(input));
    }

    [Theory]
    [InlineData(3)]
    [InlineData(6)]
    [InlineData(9)]
    public void ReturnsFizzForMultiplesOfThreeOnly(int input)
    {
        Assert.Equal("Fizz", FizzBuzz.Evaluate(input));
    }

    [Theory]
    [InlineData(5)]
    [InlineData(10)]
    [InlineData(20)]
    public void ReturnsBuzzForMultiplesOfFiveOnly(int input)
    {
        Assert.Equal("Buzz", FizzBuzz.Evaluate(input));
    }

    [Theory]
    [InlineData(15)]
    [InlineData(30)]
    [InlineData(45)]
    public void ReturnsFizzBuzzForMultiplesOfBoth(int input)
    {
        Assert.Equal("FizzBuzz", FizzBuzz.Evaluate(input));
    }
}

Run the unit tests with dotnet test from the test project folder. A passing run ends with a summary line beginning Passed! and reports zero failures. If you added a contract decision for zero or negatives, add its test here as well.

Add one integration test for the endpoint

Once the logic is exposed as a route, the failures you care about change. A unit test cannot detect a wrong route template, a missing mapping, or a response body that does not match the method’s output. An integration test calls the application over its request and response path.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Expose the Program class to the test project

Minimal API projects generate a Program class that is internal by default, so the test project cannot see it. Replace Program.cs with the following, which maps the route and makes Program visible to tests:

using FizzBuzzApi;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/fizzbuzz/{number:int}", (int number) => FizzBuzz.Evaluate(number));

app.Run();

public partial class Program { }

The route constraint {number:int} rejects non-integer segments before the handler runs, so a request for /fizzbuzz/abc returns 404 rather than reaching Evaluate.

Write the endpoint test

Create FizzBuzzEndpointTests.cs in the test project. The test uses WebApplicationFactory<Program> to host the application in memory and HttpClient to send requests to it:

using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;

public class FizzBuzzEndpointTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;

    public FizzBuzzEndpointTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    [Theory]
    [InlineData(4, "4")]
    [InlineData(9, "Fizz")]
    [InlineData(10, "Buzz")]
    [InlineData(30, "FizzBuzz")]
    public async Task GetFizzBuzzReturnsExpectedText(int number, string expected)
    {
        var response = await _client.GetAsync($"/fizzbuzz/{number}");

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(expected, await response.Content.ReadAsStringAsync());
    }
}

The endpoint test uses a few values from each category rather than the full set of unit-test cases. Its job is to confirm the wiring, so duplicating every arithmetic case would only slow the suite down. Run dotnet test again and confirm that the new class appears in the output alongside the unit tests.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What each test layer catches

Aspect Unit tests (FizzBuzzTests) Integration test (FizzBuzzEndpointTests)
Scope The Evaluate method alone The running application, from route matching to response body
Setup No web host; a direct method call WebApplicationFactory<Program> starts the application in memory
Speed and feedback Fast, and points directly at the rule that broke Slower, and points at routing, hosting, or serialization
Typical failures caught Wrong order of checks, wrong output for a number, broken exception on invalid input Missing or misspelled route, wrong route constraint, unexpected status code, changed response body

Keep the arithmetic in unit tests and the route in integration tests. When a case fails in the integration test but passes in the unit tests, the problem is in the web layer, not the rule.

Troubleshooting common failures

  • Error CS0122 saying Program is inaccessible: the public partial class Program { } line is missing from Program.cs. Add it at the end of the file.
  • 404 Not Found from the endpoint test: the request path does not match the route template. Check that the test sends /fizzbuzz/{number} and that the route in Program.cs begins with the same segment.
  • Package or framework version errors: Microsoft.AspNetCore.Mvc.Testing must match the target framework of the web project. Mismatched 8.0 and 10.0 packages are a common cause.
  • No tests discovered: confirm the test project was created from the xUnit template, so it includes the test SDK and the xUnit runner, and that the test classes are public.
  • The unit test for 15 returns Fizz: the 3 check is above the 15 check. Move the combined check to the top of Evaluate.

Microsoft’s guidance states the principle behind this split: “Use unit tests for routine tests of method logic that interact with these components.”

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.