Testing And Benchmarking in C#

Here’s the translation of the Go code to C# with explanations in Markdown format suitable for Hugo:

Unit testing is an important part of writing principled C# programs. The Microsoft.VisualStudio.TestTools.UnitTesting namespace provides the tools we need to write unit tests, and the dotnet test command runs tests.

For the sake of demonstration, this code is in a single file, but it could be split into separate files. Testing code typically lives in a separate project from the code it tests.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

public class IntUtils
{
    public static int IntMin(int a, int b)
    {
        return a < b ? a : b;
    }
}

[TestClass]
public class IntUtilsTests
{
    [TestMethod]
    public void TestIntMinBasic()
    {
        int ans = IntUtils.IntMin(2, -2);
        Assert.AreEqual(-2, ans, "IntMin(2, -2) = {0}; want -2", ans);
    }

    [TestMethod]
    public void TestIntMinTableDriven()
    {
        var tests = new[]
        {
            new { a = 0, b = 1, want = 0 },
            new { a = 1, b = 0, want = 0 },
            new { a = 2, b = -2, want = -2 },
            new { a = 0, b = -1, want = -1 },
            new { a = -1, b = 0, want = -1 },
        };

        foreach (var tt in tests)
        {
            var testName = $"{tt.a},{tt.b}";
            var ans = IntUtils.IntMin(tt.a, tt.b);
            Assert.AreEqual(tt.want, ans, $"{testName}: got {ans}, want {tt.want}");
        }
    }
}

A test is created by writing a method with the [TestMethod] attribute in a class marked with the [TestClass] attribute.

Assert.AreEqual will report test failures but continue executing the test. Assert.Fail can be used to report test failures and stop the test immediately.

Writing tests can be repetitive, so it’s common to use a data-driven style, where test inputs and expected outputs are listed in a collection and a single loop walks over them and performs the test logic.

Benchmark tests in C# are typically done using a separate benchmarking framework like BenchmarkDotNet. Here’s an example of how you might set up a benchmark:

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

public class IntUtilsBenchmark
{
    [Benchmark]
    public void BenchmarkIntMin()
    {
        IntUtils.IntMin(1, 2);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<IntUtilsBenchmark>();
    }
}

To run all tests in the current project in verbose mode:

$ dotnet test --verbosity normal

To run benchmarks (assuming you’ve set up BenchmarkDotNet):

$ dotnet run -c Release

This will compile the project in Release mode and run the benchmarks, providing detailed performance statistics.

The exact output will depend on your system, but it will include information about the number of iterations, the time per operation, and other relevant statistics.