2009-06-23 3 views
1

可能性の重複:
Writing “unit testable” code?ユニットテストを使用して簡単にテストできるようにアプリケーションを設計するにはどうすればよいですか?

私はユニットテストに新しいです。今日では、私はinterfaces in c#についての質問に対する答えを見つけました。それは、設計によってテスト可能なアプリケーションを構築するためのベストプラクティスについて考えてくれました。

私が扱っているメインアプリケーションでは、インターフェイスを非常に軽く使用しています。各クラスが他のクラス、つまり他のクラスの実装に直接依存するため、テストデータをほとんどのクラスに注入する方法がないため、テストすることが非常に困難になりました。

私の質問は、C#アプリケーションの場合、クラスと実装をどのように設計するのかと、各メソッドまたはクラスのテストデータを提供することでメソッドとクラスを個別にテストできるツールを教えてください。

EDIT:具体的には、私がリンクしている質問を見ると、答えはこれを使用します: IWidget w = ObjectFactory.GetInstance();

私はクラス/オブジェクトファクトリを一度も使用しませんでした。その動作と実装方法が不思議です。

+0

クリス、この質問が最近頼まれました:http://stackoverflow.com/questions/1007458/writing-unit-testable-コード。これは見つけるのが簡単で、単体テストを探していました。 –

+0

ありがとうございます。私はすばやい検索をしましたが、私が見たすべての結果は特定の単体テストに関するものでした。重複して申し訳ありません。 –

答えて

4

Dependency Injectionを供給するために

+0

この非常に徹底的な説明をありがとうございます。私は間違いなくこのことについてさらに研究する必要があります。 –

+0

あなたの大歓迎です。 :)私はしばらくの間、私のStackOverflowラウンドを行うチャンスを持っていない...あなたは私の最初の答えの利点を数日で得た。 – jrista

1

Dependency Injectionは、必要に応じてmock objectsを定義することで簡単にテストを作成できる優れた原則です。

基本的な考え方は、オブジェクトに依存するものを渡し、操作対象のオブジェクトを作成しないことです。テストデータ

http://ayende.com/projects/rhino-mocks.aspx 
http://code.google.com/p/moq/ 
-1

使用モックフレームワークは、あなたが探しているソリューションです。一般的な問題は、依存関係が作成される場所と関係しています。通常、オブジェクト指向のプログラムを書くとき、あなたの依存関係が必要な場所で新しいキーワードを使って依存関係を直接作成するのが自然な本能です。場合によっては、コンストラクタ内に長期間の依存関係を作成することがあります。

クラスをユニット単位でテスト可能にするには、その標準を「逆転」し、外部から依存関係を作成する必要があります(または、他の依存関係のインスタンスを作成するために注入/それらの依存関係をクラスに「注入」します。 2つの最も一般的な注入メカニズムは、コンストラクタへのパラメータとして、またはセッタでのプロパティとしてのいずれかです。このように依存関係管理を外部化することで、それらの依存関係の模擬バージョンを簡単に作成して渡すことができ、アプリケーションの残りの部分から完全に分離してコード単位をテストできるようになります。

依存性注入をサポートし、管理を容易にするためにInversion of Control(IoC)コンテナが登場しました。 IoCコンテナは、これらのグラフに参加するクラスとは独立して依存関係グラフを構成するためのフレームワークです。依存関係グラフが設定されると(通常、関心のある単一のキークラスに根ざしています)、実行時にオブジェクトのインスタンスを簡単に作成することができ、必要な依存関係もすべて手動で作成することを心配する必要はありません。これは、再構成が容易で、非常に疎結合で柔軟なコードを作成するのに役立ちます。非常に優れたIoCコンテナの例はCastle Windsorです。これは、依存関係注入によってクラスを配線するための非常に豊富なフレームワークを提供します。

依存性の注入の非常に単純な例では、次のようになります。

interface ITaskService 
{ 
    void SomeOperation(); 
} 

interface IEntityService 
{ 
    Entity GetEntity(object key); 
    Entity Save(Entity entity); 
} 

class TaskService: ITaskService 
{ 
    public TaskService(EntityServiceFactory factory) 
    { 
     m_factory = factory; 
    } 

    private EntityServiceFactory m_factory; // Dependency 

    public void SomeOperation() // Method must be concurrent, so create new IEntityService each call 
    { 
     IEntityService entitySvc = m_factory.GetEntityService(); 
     Entity entity = entitySvc.GetEntity(...); 
     // Do some work with entity 
     entitySvc.Save(entity); 
    } 
} 

class EntityServiceFactory 
{ 
    public EntityServiceFactory(RepositoryProvider provider) 
    { 
     m_provider = provider; 
    } 

    private RepositoryProvider m_provider; // Dependency 

    public virtual IEntityService GetEntityService() 
    { 
     var repository = m_provider.GetRepository<Entity>(); 
     return new EntityService(repository); 
    } 
} 

class EntityService: IEntityService 
{ 
    public EntityService(IEntityRepository repository) 
    { 
     m_repository = repository; 
    } 

    private IEntityRepository m_repository; // Dependency 

    public Entity GetEntity(object key) 
    { 
     if (key == null) throw new ArgumentNullException("key"); 

     // TODO: Check for cached entity here? 

     Entity entity = m_repository.GetByKey(key); 
     return entity; 
    } 

    public Entity Save(Entity entity) 
    { 
     if (entity == null) throw new ArgumentNullException(entity); 

     if (entity.Key == null) 
     { 
      entity = m_repository.Insert(entity); 
     } 
     else 
     { 
      m_repository.Update(entity); 
     } 

     return entity; 
    } 
} 

class RepositoryProvider 
{ 
    public virtual object GetRepository<T>() 
    { 
     if (typeof(T) == typeof(Entity)) 
      return new EntityRepository(); 
     else if (...) 
      // ... etc. 
    } 
} 

interface IEntityRepository 
{ 
    Entity GetByKey(object key); 
    Entity Insert(Entity entity); 
    void Update(Entity entity); 
} 

class EntityRepository: IEntityRepository 
{ 
    public Entity GetByKey(object key) 
    { 
     // TODO: Load up an entity from a database here 
    } 

    public Entity Insert(Entity entity) 
    { 
     // TODO: Insert entity into database here 
    } 

    public void Update(Entity entity) 
    { 
     // TODO: Update existing entity in database here 
    } 
} 
関連する問題