Unity 和 NUnit

Unity and NUnit

我正在尝试对书面方法执行单元测试,但我遇到了问题。

这是我的 UnityConfig class:

public class UnityConfig
{
    #region Unity Container
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }
    #endregion

    public static void RegisterTypes(IUnityContainer container)
    {
        container.RegisterInstance(AutoMapperConfig.Initialize());
        container.RegisterType<IActiveDirectoryUserService, ActiveDirectoryUserService>();
        container.RegisterType<IUserRepository, InMemoryUserRepository>();
        container.RegisterType<IUserService, UserService>();
    }
}

测试方法:

public async Task RegisterAsync(string name, string email, string firstName, string lastName, string password)
{
    var user = await _userRepository.GetBynameAsync(name);

    if (user != null)
    {
        throw new Exception($"User {name} already exists.");
    }
    else
    {
        var ActiveDirectoryUser = await _ActiveDirectoryUserService.GetBynameAsync(name);

        if (ActiveDirectoryUser == null)
        {
            throw new Exception($"User {name} does not exist in Active Directory");
        }
        else
        {
            var salt = new Guid().ToString("N");
            user = new User(name, ActiveDirectoryUser.Email, ActiveDirectoryUser.FirstName, ActiveDirectoryUser.LastName, password, salt);
            await _userRepository.AddAsync(user);
        }
    }
}

测试方法:

[Test]
public async Task Test()
{
    var userRepositoryMock = new Mock<IUserRepository>();
    var activeDirectoryUserMock = new Mock<IactiveDirectoryUserService>();
    var mapperMock = new Mock<IMapper>();

    var userService = new UserService(userRepositoryMock.Object, activeDirectoryUserMock.Object, mapperMock.Object);

    await userService.RegisterAsync("name", "user@emial.com", "first name", "last name", "password");

    userRepositoryMock.Verify(x => x.AddAsync(It.IsAny<User>()), Times.Once);
}

经过测试的方法在外部测试中运行良好,但是当我运行 测试时它失败了。我运行在调试模式下测试,我发现它没有进入

var user = await _userRepository.GetBynameAsync(name);

var ActiveDirectoryUser = await _ActiveDirectoryUserService.GetBynameAsync(name);

知道为什么它在测试期间不进入这些方法吗?我是否需要向 UnityConfig 添加一些条目才能使其正常工作?

-- 编辑

private static ISet<User> _users = new HashSet<User>
{
    new User("user1", "ab@rmail.com", "firstnam1", "lastname1", "pass", "salt"),
    new User("user2", "ac@rmail.com", "firstnam2", "lastname2", "pass", "salt"),
    new User("user3", "ad@rmail.com", "firstnam3", "lastname3", "pass", "salt")
};

public async Task<IEnumerable<User>> GetAllAsync()
    => await Task.FromResult(_users);

发生的事情是模拟不知道如何从异步调用中 return 所以当代码试图等待它们时它失败了。它不一定与您的 DI 容器有关。它不存在于此单元测试中。

做出一些假设,因为没有提供足够的关于测试中使用的类型的信息。

给定被测方法,让我们假设您有这样的界面

public interface IUserRepository {
    Task<User> GetByNameAsync(string name);
    Task AddAsync(User user);
}
public interface IActiveDirectoryUserService {
    Task<AdUserAccount> GetByNameAsync(string name);
}
public class AdUserAccount {
    public  string Email { get; set; }
    public  string FirstName { get; set; }
    public  string LastName { get; set; }
}

注意 return 一个 Task 的方法。

您需要设置模拟以了解如何处理异步调用并允许任务完成。

[Test]
public async Task Test() {
    //Arrrange
    var name = "name";
    var email = "user@emial.com";
    var firstname = "first name";
    var lastname = "last name";

    var userRepositoryMock = new Mock<IUserRepository>();
    //Testing that it returns no user for that name so return null from async call
    userRepositoryMock.Setup(_ => _.GetByNameAsync(name)).ReturnsAsync((User)null);
    //Need this to make sure async call runs to completion
    userRepositoryMock.Setup(_ => _.AddAsync(It.IsAny<User>())).Returns(Task.FromResult((object)null));

    var activeDirectoryUserMock = new Mock<IActiveDirectoryUserService>();
    //fake account for mock AD call
    var adUser = new AdUserAccount {
        Email = email,
        FirstName = firstname,
        LastName = lastname
    };            
    //Need fake ad account to return from async call
    activeDirectoryUserMock.Setup(_ => _.GetByNameAsync(name)).ReturnsAsync(adUser);

    var mapperMock = new Mock<IMapper>();

    var userService = new UserService(userRepositoryMock.Object, activeDirectoryUserMock.Object, mapperMock.Object);

    //Act
    await userService.RegisterAsync(name, email, firstname, lastname, "password");

    //Assert
    userRepositoryMock.Verify(x => x.AddAsync(It.IsAny<User>()), Times.Once);
}