Tim Deschryver

Refactor Functional Tests to support Minimal Web APIs

Modified
@tim_deschryver

I really like to write functional tests for my code. The biggest reason is that each test represents a client that interacts with the application. Just like a real client, the test doesn't care about the internal details of the application. The test only cares about the result.

Because of it, existing test cases don't need to be touched while we're refactoring the code base, for example, when we're migrating to the new ASP.NET 6 Minimal Web API structure.

To be fair... in this case, some small changes are required. Luckily, these changes are minor and are only affecting the setup of the tests suites. The tests themselves remain untouched. This gives us the confidence to ship our application when the migration is complete.

In How to test your C# Web API we learned how to write functional tests. To freshen up our memory, here's the base setup that is used in that article.

If you look closely, you'll notice that the WebApplicationFactory is created by using the Startup type from the Web API project. This causes to be the problem because Startup doesn't exist anymore in a Minimal Web API.

More info about the new structure in Maybe it's time to rethink our project structure with .NET 6.

Fortunately, this doesn't mean that we have to rethink and rewrite our tests (setup).

Reference a Minimal Web API

There is one special file in a Minimal Web API, which is the one that uses top-level statements (there can only be one file like this). This file can be referenced as Program, and unusually the file is also named Program.cs (the name of the file doesn't affect the Program type name).

This Program type has the internal access modifier and thus can't be referenced from outside the project by default. To make it accessible in the test project, we need to give the test project access to the internals of the API Project. This is done by adding an InternalsVisibleTo attribute to the API csproj.

Afterward, the Program type (instead of Startup) can be used in the test project to create the application.

But we're not there yet. When we try to create the application by using Project, we get the compile error CS0060.

This can quickly be fixed by also modifying the access modifier of our class to internal.

If you're manually spawning new applications then you're job is done here. You can now spawn a new instance of the API application and test it, just like before.

Though, another problem appears with this code if you're using XUnit fixtures to create the API application. It might be worthwhile to continue to read, even if you're not using XUnit, because the following solution might have your preference.

Working with XUnit Fixtures

Because we've changed the test's class to internal, we get the next compiler error, xUnit1000 Test classes must be public.

The workaround for this is to reference a public type from the API project. This can be any type you'd want, but it seems like creating your own Program type is the desired way to do this.

After this, we can revert the changes to make the internals of the API projects visible. Next, the Program type can now be referenced to create the fixture.

The final step is to run the tests again and make sure they're all turning green.

Happy upgrading!

Outgoing links

Please consider supporting me if have you enjoyed this post and found it useful:

Buy Me A Coffee PayPal logo
Support the blog Share on Twitter Discuss on Twitter Edit on GitHub