rexcfnghk rexcfnghk -4 years ago 150
C# Question

Async lambda expressions in Xunit Assert.Throws

I have some test code asserting duplicate

User
s cannot be created through my
UserRepository
.

User.cs:

public class User
{
public int Id { get; set; }

public string AccountAlias { get; set; }

public string DisplayName { get; set; }

public string Email { get; set; }

public bool IsActive { get; set; }
}


UserRepository.cs:

public class UserRepository
{
public virtual async Task<User> CreateAsync(User entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}

if (await GetDuplicateAsync(entity) != null)
{
throw new InvalidOperationException("This user already exists");
}

return Create(entity);
}

public async Task<User> GetDuplicateAsync(User user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}

return await (from u in Users
where u.AccountAlias == user.AccountAlias &&
u.Id != user.Id &&
u.IsActive
select u).FirstOrDefaultAsync();
}
}


UserRepositoryTests.cs:

public sealed class UserRepositoryTests : IDisposable
{
public UserRepositoryTests()
{
UserRepository = new UserRepository(new FooEntities()); // DbContext
// from EF
}

private UserRepository UserRepository { get; set; }

[Fact]
public void DuplicateUserCannotBeCreated()
{
var testUser = new User // This test user already exists in database
{
Id = 0,
AccountAlias = "domain\\foo",
DisplayName = "Foo",
Email = "foo@bar.com",
IsActive = true
};
Assert.Throws<InvalidOperationException>(async () =>
await UserRepository.CreateAsync(testUser));
}

public void Dispose()
{
if (UserRepository != null)
{
UserRepository.Dispose();
}
}
}


When I run this unit test,
Xunit.Sdk.ThrowsException
is thrown (i.e. my
InvalidOperationException
was not thrown):


Assert.Throws() Failure
Expected: System.InvalidOperationException
Actual: (No exception was thrown)


From the debugger,
GetDuplicateAsync()
was evaluated but when the LINQ query was executed, the result was never returned and thus no exception was thrown. Can anyone help?

Answer Source

xUnit's Assert.Throws (at least on version 1.9.2) is not async-aware. This was fixed in version 2, which now has an Assert.ThrowsAsync method.

So, you can either upgrade to xUnit 2 or create your own method to get it working:

public async static Task<T> ThrowsAsync<T>(Func<Task> testCode) where T : Exception
{
    try
    {
        await testCode();
        Assert.Throws<T>(() => { }); // Use xUnit's default behavior.
    }
    catch (T exception)
    {
        return exception;
    }
    return null;
}

await ThrowsAsync<InvalidOperationException>(async () => await UserRepository.CreateAsync(testUser));

From Haacked's gist.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download