4

モックと依存性注入に関する質問やブログをざっと見てみました。結論として、クライアントが消費するインターフェイスをモックするだけで済みます。ここで単純なユースケースをテストすることを楽しみにしています。

その契約

public Interface IApplicationService
{

     bool DeleteApplication(int id);

     ApplicationDto AddApplication(ApplicationDto application);

     IEnumerable<ApplicationDto> GetApplications();

}

実装(私はモックするつもりです)

public Class ApplicationService:IApplicationService
{
    private EntityFrameworkRepo repo; 

    public ApplicationService()
    {
         repo = new EntityFrameworkRepo();
    }

    public ApplicationDto Add(ApplicationDto dto)
    {
         //add to dbcontext and commit
    }

}

モッキングコード

[Test(Description = "Test If can successfully add application")]
public void CanAddApplication()
{
    //create a mock application service
    var applicationService = new Mock<IApplicationService>();

    //create a mock Application Service to be used by business logic
    var applicationDto = new Mock<ApplicationDto>();

    //How do i set this up
    applicationService.Setup(x => x.GetApplications()).Returns(IEnumerable<applicationDto.Object>);
}

そして、ビジネスロジックをモックするのではなく、テストする必要があると確信しています。それで、私をテストするために正確に何をしなければなりませんがApplicationService、エンティティフレームワークを締め出します。

ところでApplicationService、それは NInject でコンストラクター注入を使用します。これをモックすると、NInject.MockingKernel依存関係チェーンがセットアップされますか?

4

1 に答える 1

6

単体テストで依存性注入 (IOC) コンテナーを使用する利点はほとんどまたはまったくありません。依存性注入は疎結合コンポーネントの作成に役立ち、疎結合コンポーネントはテストが容易です。

したがって、いくつかのサービスをテストしたい場合は、その依存関係のモックアップを作成し、通常どおりそのサービスに渡します (ここで IOC コンテナーを使用する必要はありません。コンテキスト バインディングなど、IOC コンテナーのいくつかの機能が必要になることはほとんど想像できません)。 、傍受など - 単体テスト内)。

ApplicationServiceテストを簡単にしたい場合は、次のようにする必要があります。

public class ApplicationService: IApplicationService
{
    private readonly IEntityFrameworkRepo repo; 

    // dependency passed by constructor
    public ApplicationService(IEntityFrameworkRepo repo)
    {
         this.repo = repo;
    }

    // save to db when DTO is eligible
    public ApplicationDto Add(ApplicationDto dto)
    {
         // some business rule
         if(dto.Id > 0 && dto.Name.Contains(string.Empty)){
              //add to dbcontext and commit
         }else{
              throw new NotEligibleException();
         } 
    }   
}

ここで、依存関係はコンストラクターによって渡されます。アプリケーション コードでは、これを IOC コンテナーと一緒に使用して、コンストラクター インジェクションを行います (IOC コンテナーは のインスタンスの作成を担当しますIEntityFrameworkRepo)。

ただし、単体テストではIEntityFrameworkRepo、独自に作成した実装のインスタンスを渡すだけです。

ApplicationDto

手動で作成できるオブジェクトである限りApplicationDto、単体テスト (インスタンスを手動で作成) で直接使用できます。IApplicationDtoそれ以外の場合は、Moq でモックアップできるように、 のようなインターフェイスでラップする必要があります。

public class ApplicationDto{
     public int Id {get; set;}
     public string Name {get; set;}
}

単体テストは次のようになります。

単体テストではIApplicationRepo、データベース接続、Web サービスなどを構成したくないため、のモック実装を使用します。私の主な目的はApplicationService、基礎となるリポジトリではなくをテストすることです。別の利点は、さまざまなマシンの特定の構成なしでテストを実行できることです。いくつかの db リポジトリをモックアップするには、たとえばList.

[Test(Description = "Test If can successfully add application")]
public void CanAddApplicationIfEligible()
{
    var repo = GetRepo();
    var appService = new ApplicationService(repo);       
    var testAppDto = new ApplicationDto() { Id = 155, Name = "My Name" };

    var currentItems = repo.ApplicationDtos.Count();

    appService.Add(testAppDto);

    Assert.AreEqual(currentItems + 1, repo.ApplicationDtos.Count());
    var justAdded = repo.ApplicationsDto.Where(x=> x.Id = 155).FirstOrDefault();
    Assert.IsNotNull(justAdded);
    ///....
}

private static IEntityFrameworkRepo GetRepo{
    // create a mock repository
    var listRepo = new List<ApplicationDto>{
                         new ApplicationDto {Id=1, Name="MyName"}               
                   };

    var repo = new Mock<IEntityFrameworkRepo>();

    // setup the methods you know you will need for testing

    // returns initialzed list instead of DB queryable like in real impl.
    repo.Setup(x => x.ApplicationDtos)
        .Returns<IQueryable<ApplicationDto>>(x=> listRepo);

    // adds an instance of ApplicationDto to list
    repo.Setup(x => x.Add(It.IsAny<ApplicationDto>())
        .Callback<ApplicationDto>(a=> listRepo.Add(a));
    return repo.Object;
}

ノート:

ninject.mockingkernel拡張機能がリリースされました。wiki の例で説明されているアプローチは、単体テスト コードを少し整理することができますが、そこで説明されているアプローチは依存性注入ではありません (サービス ロケーターです)。

于 2013-02-01T20:28:06.927 に答える