2009-02-28 8 views
1

私が書いたアプリケーションをテストするのにNUnitを使いたいのですが、私が書いたユニットテストには環境や基盤データベースへの直接リンクがあります。開発機械ではなく、NUnit環境やデータベースではなく、アプリケーションをテストする

例を挙げておきます。

私は、別のアプリケーションによってレジストリに格納されている文字列を取得するという単一の責任を持つクラスを作成しています。キーはHKCU \ Software \ CustomApplication \ IniPathに保存されます。

テストの結果は次のようになります。 ":\ PROGRAMFILES \ CustomApplication \ SomeDir C" 今、実際には正しいです

[Test] 
public void GetIniDir() 
{ 
    RegistryReader r = new RegistryReader(); 
    Assert.AreEqual(@"C:\Programfiles\CustomApplication\SomeDir", r.IniDir); 
} 

は、しかし、ここでの問題は、@文字列があることです。明日は@ "C:\ Anotherdir \ SomeDir"に変わったかもしれませんし、コードが変わっていないのに突然私の単体テストが壊れてしまいます。

この問題は、データベースに対してCRUD操作を実行するクラスを作成した場合にも発生します。データベース内のデータは常に変化する可能性があり、テストが失敗します。だから私のクラスが意図したことをしても、データベースが最初にテストを書いたときに持っていたより多くの顧客を返すので失敗するでしょう。

周囲の環境にあまり依存しないテストを書く上でのヒントはありますか?

答えて

6

この問題の解決策は、よく知られています。mockingです。インターフェイスをコードにリファクタリングしてから、偽のクラスを開発して、それらのインターフェイスを実装するか、またはRhinoMockseasyMockMoqなどの模擬フレームワークでそれらをモックします。 al。偽のクラスやモッククラスを使用すると、データベースなどの外部エンティティと実際にやりとりすることなく、インターフェイスが返すテストを定義することができます。

SOを使った模倣の詳細については、Google検索:http://www.google.com/search?q=mock+site:stackoverflow.comを試してみてください。あなたはまた、で定義で興味深いことがありますWhat's the difference between faking, mocking, and stubbing?

さらに、このような依存関係のその依存関係からあなたのクラスのデカップリングを可能に注入(@Patrikが示唆するように)、および静的オブジェクトの回避など優れた開発手法、単体テストをより困難にして、テストを容易にします。テストが最初に開発されたTDDプラクティスを使用すると、これらの設計原則を組み込んだアプリケーションを自然に開発するのに役立ちます。

0

他の方法は、テスト用に別のデータベースを作成することです。

+1

しかし、実際には単体テストではなく、統合テストです。 –

2

最も簡単な方法は、依存関係注入を使用して依存関係を明示的にすることです。たとえば、最初の例ではレジストリに依存していますが、IRegistry(定義するインターフェイス)を渡してこの依存関係を明示的にしてから、これを依存関係で渡してレジストリから読み込みます。こうすることで、IRegistry-stubを渡すことができます。これは、実際には既知の値を返すテストです。実際には、レジストリから実際に読み取る実装を使用します。

public interface IRegistry 
{ 
    string GetCurrentUserValue(string key); 
} 

public class RegistryReader 
{ 
    public RegistryReader(IRegistry registry) 
    { 
     ... 
     // make the dependency explicit in the constructor. 
    } 
} 
[TestFixture] 
public class RegistryReaderTests 
{ 
    [Test] 
    public void Foo_test() 
    { 
     var stub = new StubRegistry(); 
     stub.ReturnValue = "known value"; 

     RegistryReader testedReader = new RegistryReader(stub); 

     // test here... 
    } 

    public class StubRegistry 
     : IRegistry 
    { 
     public string ReturnValue; 

     public string GetCurrentUserValue(string key) 
     { 
      return ReturnValue; 
     } 
    } 
} 

この簡単な例では、手動スタブを使用していますが、もちろんこれには任意のモックフレームワークを使用できます。

0

制御原理の逆転と、依存性注入手法の使い方を読み、実際にテスト可能なコードを書くのに役立ちます。

あなたの場合、おそらくインターフェイスが必要です。 IIniDirProvider - これはRegistryBasedIniDirProviderによって実装され、レジストリの特定のキーに基づいて初期ディレクトリを提供することができます。あなたはユニットテストSomeOtherClassに必要がある場合

public SomeOtherClass(IIniDirProvider iniDirProvider) 
{ 
    this.iniDirProvider = iniDirProvider; 
} 

はモックIIniDirProviderに渡すことができ-allowing:いくつかの他のクラスは他のクラスには、次のctorを持っている必要があることを、初期ディレクトリを検索する必要が続いて

、 。そうすれば、ユニットテストはレジストリに存在するものに依存しません。

関連する問題