Await Tasks in Test Setup Code in xUnit.net?

C#Async Awaitxunit.net

C# Problem Overview


The exact situation is I'm doing E2E tests with Protractor.NET (.NET port of AngularJS's Protractor E2E framework) and I would like to make some web requests (and the API -- System.Net.Http.HttpClient -- has all Async/Task methods) to Arrange my test before I Act/Assert, only I need to do this same Arrange-ing for several tests.

I'm using xUnit.net as my test runner they use an interface (IUseFixture<T>) for per-fixture setup code. It would be nice if there was a IAsyncUseFixture<T> that had a Task SetFixtureAsync(T t); or something. I don't think such a thing exists. Additionally I don't think constructors can use await either, and constructors are the only other way to execute the same block of code per-test in xUnit.net.

What are my options? .Result? Isn't that bad practice (deadlock)?

C# Solutions


Solution 1 - C#

xUnit has an IAsyncLifetime interface for async setup/teardown. The methods you need to implement are Task InitializeAsync() and Task DisposeAsync().

InitializeAsync is called immediately after the class has been created, before it is used.

DisposeAsync is called just before IDisposable.Dispose if the class also implements IDisposable.

e.g.

public class MyTestFixture : IAsyncLifetime
{
	private string someState;

	public async Task InitializeAsync()
	{
		await Task.Run(() => someState = "Hello");
	}

	public Task DisposeAsync()
	{
		return Task.CompletedTask;
	}
		
	[Fact]
	public void TestFoo()
	{
		Assert.Equal("Hello", someState);
	}
}

Solution 2 - C#

I would use AsyncLazy

http://blog.stephencleary.com/2012/08/asynchronous-lazy-initialization.html

In my case I want to run some integration tests against a self hosted web api.

public class BaseTest() 
{
    private const string baseUrl = "http://mywebsite.web:9999";

    private static readonly AsyncLazy<HttpSelfHostServer> server = new AsyncLazy<HttpSelfHostServer>(async () =>
    {
        try
        {
            Log.Information("Starting web server");
            
            var config = new HttpSelfHostConfiguration(baseUrl);

            new Startup()
                .Using(config)
                .Add.AttributeRoutes()
                .Add.DefaultRoutes()
                .Remove.XmlFormatter()
                .Serilog()
                .Autofac()
                .EnsureInitialized();

            var server = new HttpSelfHostServer(config);
            await server.OpenAsync();

            Log.Information("Web server started: {0}", baseUrl);

            return server;
        }
        catch (Exception e)
        {
            Log.Error(e, "Unable to start web server");
            throw;
        }
    });

    public BaseTest() 
    {
        server.Start()
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJesus is LordView Question on Stackoverflow
Solution 1 - C#WilkaView Answer on Stackoverflow
Solution 2 - C#superlogicalView Answer on Stackoverflow