1

私はユニットテストが初めてで、ユニットテストメソッドを次のように書く方法を混乱させています。

public Boolean BeepInTime(Interfaces.IDateTime time,TimeSpan beepTime)
{
    Interfaces.IBeep beep= new Beep();
    var h = time.GetTime();
    if (h == beepTime)
    {
       return beep.Beeping();
    }
    else
    {
       return false;
    }
}

public Boolean Beeping()
{
    try
    {
      SystemSounds.Beep.Play();
      return true;
    }
    catch
    {
      return false;
    }
}

をテストするときBeepInTimeは、( beep.Beeping()) を実行しないでください。スタブについて読んで、この場合はスタブを使用する必要があると思いますが、これを行う方法がわかりにくいです。スタブに関する簡単な例を含むソースを送っていただけますか。

4

3 に答える 3

4

解決策は - 依存性注入です。

依存性注入について考えたり (構築) したりするたび... = new ...();に、基本的に明示的なインスタンス化によって依存性が導入され、そのようなコードの単体テストを作成することが簡単ではなくなることがあります。

したがって、Beepクラスの明示的なインスタンス化の代わりに、それを注入するだけです。何が良いか - あなたはすでにこのクラスを抽象化するインターフェースを持っています -IBeepこれにより、単体テストを書くときに実際のクラスインスタンスの代わりにモックを作成して注入することができます。

public Boolean BeepInTime(Interfaces.IBeep beeper, TimeSpan beepTime) 
{
    var h = time.GetTime();            
    if (h == beepTime)            
    {                 
        return beep.Beeping();            
    } 

    return false;
}

DB アクセス サービスまたは Web サービスを注入する場合に、この手法がどのように役立つか想像してみてください。単体テストの作成中に実際の DB または Web サービスは必要ありません。DB/Web サービスをモックするだけで、それだけです。

RhinoMocks を使用した例:

var mock = MockRepository.GenerateMock<IBeep>();

// setup Beeping() return value == true
mock.Expect(m => m.Beeping()).Return(true);
var isBeepInTime = BeepInTime(mock, timeSpan)
于 2012-09-07T13:28:26.753 に答える
3

これを解決するには、さまざまな方法があります。最も簡単な方法は、Beep へのインターフェイスを (コンストラクターまたはメソッド自体を介して) クラスに渡すことです。

public Boolean BeepInTime(Interfaces.IDateTime time,TimeSpan beepTime, Interfaces.IBeep beep) 
{ 
    var h = time.GetTime(); 
    if (h == beepTime) 
    { 
        return beep.Beeping(); 
    } 
    else 
    { 
        return false; 
    } 
   } 

単体テストでは、モック IBeep オブジェクトを作成し、モックに渡します。サードパーティのモッキング フレームワークも多数あるため、独自のモックを作成する必要はありません。私は個人的にMoqを使用していますが、それは良いものです。RhinoMocksも人気です。どちらも無料です。

本番コードで Beep クラスを作成する必要がない場合は、これを行うことができます...

public Boolean BeepInTime(Interfaces.IDateTime time,TimeSpan beepTime, Interfaces.IBeep beep = null) 
{ 
    if (beep == null)
         beep = new Beep();

    var h = time.GetTime(); 
    if (h == beepTime) 
    { 
        return beep.Beeping(); 
    } 
    else 
    { 
        return false; 
    } 
   } 

注: 通常、インターフェイスをコンストラクターに渡してフィールドに代入するのではなく、メソッドに渡すのではなく、特にクラスが多くのメソッドから呼び出される場合)。これを行うには、NInject を使用するなど、他にも多くの方法があります。これらの例を提供しているのは、それがどのように行われるかをこっそりと見ていただくためです。

いずれかの方法を決定する前に、これらのことを調べるためにインターネットで数日間の調査を行うことをお勧めします.

于 2012-09-07T13:26:50.790 に答える
2

最初に、次のようにメソッドBeepから依存関係を削除する必要があります。BeepInTime

public Boolean BeepInTime(Interfaces.IDateTime time,TimeSpan beepTime, Interfaces.IBeep beep)
       {           
           var h = time.GetTime();
           if (h == beepTime)
           {

               return beep.Beeping();
           }
           else
           {
               return false;
           }

       }

次に、Moq のようなものを使用してテストするときに、IBeep 実装をモックアウトできます。

//Arrange
var mockBeep = new Mock<Interfaces.IBeep>();
mockBeep.Setup(b => b.Beeping())
.Returns(true);

// Act

var result = myClass.BeepInTime(myTime, myBeepTime, mockBeep.Object);

...
于 2012-09-07T13:31:48.330 に答える