سؤال

I have some test code asserting duplicate Users 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?

هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

XUnit now handle Assert.ThrowAsync by default

This works for me:

Assert.Throws<AbpValidationException>(() => _personAppService.CreatePersonAsync(new CreatePersonInput { Name = null }));

Just don't use async/await.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top