.NET by Kurt

Testing in .NET

Automated testing in .NET is a crucial software development practice that involves using specialized tools and frameworks to create and execute tests automatically. It verifies the correctness of code, detects bugs early in the development process, and ensures that changes do not introduce new issues. .NET offers robust testing libraries like MSTest, NUnit, and xUnit, along with tools like Visual Studio Test Explorer, to simplify the creation and execution of unit, integration, and UI tests, enhancing the reliability and maintainability of .NET applications.

...see more

In the .Net Framework, the approach to unit testing internal methods or types was to add an InternalsVisibleTo attribute into the AssemblyInfo.cs file. For example, look at the following line of code below:

InternalsVisibleTo Attribute

[assembly: InternalsVisibleTo("Projects.Tests")]

This all works fine in the .net Framework. However, in .Net Core, most of the settings in the AssemblyInfo file have been moved to the project file. So, to test internal methods, you have two options.

Project File Change

Assuming we have a project called Projects and a unit test project called Projects.Tests. The Projects project file, which contains the internal method, can be modified in Visual Studio with the following:

AssemblyAttribute

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>Projects.Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Starting with .NET 5, you can use the <InternalsVisibleTo> without adding any NuGet package:

<ItemGroup>
    <InternalsVisibleTo Include="Projects.Tests" />
</ItemGroup>

Source File change

The alternative way is to use an attribute in the source file containing the internal method. For example, see the code below:

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Projects.Test")]

namespace Projects
{
    public class User
    {
        internal string Hello(string username)
        {
            return $"Hello {username}";
        }
    }
}

Additional Resources:

...see more

This is a unit test method written in C# using the xunit framework. It is testing the behavior of a method named GetFolderAsync from a class called FileSystem.

[Fact( DisplayName = "get folder async should throw exception for non-existent folder" )]
public async Task GetFolderAsyncShouldThrowExceptionForNonExistentFolder()
{
    var fileSystem = new FileSystem();
    var ex = await Assert.ThrowsAsync<DirectoryNotFoundException>( () => fileSystem.GetFolderAsync( @"C:\blah" ) );
}

This xUnit test method is named "GetFolderAsyncShouldThrowExceptionForNonExistentFolder." It is an asynchronous test that checks whether calling the GetFolderAsync method on a fileSystem object with the path @"C:\blah" results in a DirectoryNotFoundException being thrown. The [Fact] attribute marks it as a fact test case, and the DisplayName attribute provides a custom name for the test. This test aims to ensure that the GetFolderAsync method correctly throws an exception when trying to access a non-existent folder.

...see more

When writing unit tests in .NET using Assert.Contains, it's easy to accidentally check for exact matches when you only want to check if a string is part of another.

Here’s a common mistake:

Assert.Contains("TestCookie=TestValue", cookieStrings);

This fails if cookieStrings contains items like "TestCookie=TestValue; Path=/; HttpOnly" — because "TestCookie=TestValue" is not an exact match to any item.

How to Fix It

Use the lambda version of Assert.Contains to check for a substring match:

Assert.Contains(cookieStrings, c => c.Contains("TestCookie=TestValue"));

This makes sure that at least one string in the collection includes "TestCookie=TestValue" somewhere inside it.

Example Use Case

In a test where you're adding a cookie to an HttpClient, you might write:

Assert.Contains(
    httpClient.DefaultRequestHeaders.GetValues("Cookie"),
    c => c.Contains("TestCookie=TestValue")
);

Summary

  • Assert.Contains(item, collection) checks for exact matches.
  • Use Assert.Contains(collection, predicate) to check for substring matches.
  • Ideal for validating headers, cookies, or complex strings in collections.
...see more

What’s the Problem?

When writing unit tests for a custom DelegatingHandler, you might try calling:

var response = await handler.SendAsync(request, cancellationToken);

But this will cause a compiler error. Why? Because SendAsync in DelegatingHandler is protected, meaning you can't call it directly from your test project.

The Simple Solution

Use HttpMessageInvoker, which is designed to work with any HttpMessageHandler (including DelegatingHandler). It provides a public SendAsync method, so you can easily test your handler:

var handler = new YourCustomHandler
{
    InnerHandler = new DummyHandler() // Replace with mock/stub as needed
};

var invoker = new HttpMessageInvoker(handler);
var response = await invoker.SendAsync(request, cancellationToken);

This allows you to simulate HTTP requests through your custom handler, without using HttpClient.

Why This Works

  • DelegatingHandler is a subclass of HttpMessageHandler.
  • HttpMessageInvoker takes any HttpMessageHandler and exposes a public way to send HTTP requests.
  • This bypasses the visibility issue with protected SendAsync.

Tip for Better Testing

Use a mock InnerHandler to control the behavior of the response. This helps you test how your DelegatingHandler reacts to different scenarios.

Comments