2017-06-26 19 views
1

私は単体テストを書かれたメソッドにしようとしていますが、私は問題に直面しています。ここでUnityとNUnit

は私のUnityConfigクラスです:

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", "[email protected]", "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にいくつかのエントリを追加して動作させる必要がありますか?

- 何が起こっているEDIT

private static ISet<User> _users = new HashSet<User> 
{ 
    new User("user1", "[email protected]", "firstnam1", "lastname1", "pass", "salt"), 
    new User("user2", "[email protected]", "firstnam2", "lastname2", "pass", "salt"), 
    new User("user3", "[email protected]", "firstnam3", "lastname3", "pass", "salt") 
}; 

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

答えて

2

はモックは、コードは、それが失敗した彼らを待っしようとするときに非同期呼び出しから復帰する方法がわからないということです。必ずしもあなたのDIコンテナとは関係ありません。このユニットテストには存在しません。

テストで使用されているタイプについて十分な情報が提供されていないため、いくつかの前提があります。テスト対象の方法を考える

は、私たちがTaskを返すメソッドを注意してくださいあなたはこの

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; } 
} 

ようなインターフェイスを持っていると仮定しましょう。

非同期呼び出しを処理してタスクが完了するまでの流れを知るには、モックを設定する必要があります。

[Test] 
public async Task Test() { 
    //Arrrange 
    var name = "name"; 
    var email = "[email protected]"; 
    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); 
} 
+0

ありがとうございました。仮定したインターフェースはmintと同じように見えます。私は2つのことを理解していません。 userRepositoryMockの場合、なぜあなたはAddAsyncメソッドを呼び出していますか?また、なぜadUserMockのために偽のアカウントを作成しましたか?私はより穏やかな方法でテストを書くことができるように非同期呼び出しをサポートする他のライブラリはありますか? – ironcurtain

+0

@ironcurtain 'AddAsync'は' Task'を返します。あなたがそれを設定しなければ、モックは何も返さず、テスト中のメソッドは完了まで流れません。 – Nkosi

+0

@ironcurtain他の依存関係も同じです。正しく設定されていませんでした。テストでは、依存関係が擬似されているため、テスト中のメソッドを具体的な実装を使用することによって発生する可能性のあるノックオン効果なしに単独でテストできます。テストされるメソッドも非同期であるため、テストを配置するときに考慮する必要があります。 – Nkosi