2011-07-22 8 views
6

私はUdpClientを利用するクラスで、NUnitとMoqを使用してTDDアプローチを学習/利用しようとしています。次のようにユニットテストのためのUdpClientを模擬する

私のクラスの最低限の部分は、これまでのところです:

public UdpCommsChannel(IPAddress address, int port) 
{ 
    this._udpClient = new UdpClient(); 
    this._address = address; 
    this._port = port; 
    this._endPoint = new IPEndPoint(address, port); 
} 

public override void Open() 
{ 
    if (this._disposed) throw new ObjectDisposedException(GetType().FullName); 

    try 
    { 
     this._udpClient.Connect(this._endPoint); 
    } 
    catch (SocketException ex) 
    { 
     Debug.WriteLine(ex.Message); 
    } 
} 

public override void Send(IPacket packet) 
{ 
    if (this._disposed) throw new ObjectDisposedException(GetType().FullName); 

    byte[] data = packet.GetBytes(); 
    int num = data.Length; 

    try 
    { 
     int sent = this._udpClient.Send(data, num); 
     Debug.WriteLine("sent : " + sent); 
    } 
    catch (SocketException ex) 
    { 
     Debug.WriteLine(ex.Message); 
    } 
} 


。 Sendメソッドの場合
、私は現時点では、次のユニットテストを持っている:

[Test] 
public void DataIsSent() 
{ 
    const int port = 9600; 

    var mock = new Mock<IPacket>(MockBehavior.Strict); 
    mock.Setup(p => p.GetBytes()).Returns(new byte[] { }).Verifiable(); 

    using (UdpCommsChannel udp = new UdpCommsChannel(IPAddress.Loopback, port)) 
    { 
     udp.Open(); 
     udp.Send(mock.Object); 
    } 

    mock.Verify(p => p.GetBytes(), Times.Once()); 
} 



ローカルホストであっても実際のIPアドレスを使用しているため、クラス内のUdpClientが物理的にデータを送信しているので、それほど幸せではありません。したがって、私が理解している限り、これは真のユニットテストではありません。

問題は、私はそれについて何をすべきか正確に頭を浮かべることができません。クラスを変更し、新しいUdpClientを依存関係として渡すべきでしょうか?どういうわけかIPAddressをモックしますか?

少し苦労ので、私は私が運ぶ前に、正しい軌道に乗っていますかどうかを確認するためにここで停止する必要があります。どんなアドバイスもありがとう! (NUnitの2.5.7、部品番号4.0とC#のリサイズを使用する。)


UPDATE:次のように

OK、私は私のコードをリファクタリングしている:

public interface IUdpClient 
{ 
    void Connect(IPEndPoint endpoint); 
    int Send(byte[] data, int num); 
    void Close(); 
} 

はIUdpClientインターフェイスを作成しました。

public class UdpClientAdapter : IUdpClient 
{ 
    private UdpClient _client; 

    public UdpClientAdapter() 
    { 
     this._client = new UdpClient(); 
    } 

    #region IUdpClient Members 

    public void Connect(IPEndPoint endpoint) 
    { 
     this._client.Connect(endpoint); 
    } 

    public int Send(byte[] data, int num) 
    { 
     return this._client.Send(data, num); 
    } 

    public void Close() 
    { 
     this._client.Close(); 
    } 

    #endregion 
} 

はUdpClientシステムクラスをラップするアダプタクラスを作成しました。私UdpCommsChannelのCLASはIUdpClientのインスタンスを必要とするようにリファクタリング

は、コンストラクタを介して注入:

public UdpCommsChannel(IUdpClient client, IPEndPoint endpoint) 
{ 
    this._udpClient = client; 
    this._endPoint = endpoint; 
} 

[Test] 
public void DataIsSent() 
{ 
    var mockClient = new Mock<IUdpClient>(); 
    mockClient.Setup(c => c.Send(It.IsAny<byte[]>(), It.IsAny<int>())).Returns(It.IsAny<int>()); 

    var mockPacket = new Mock<IPacket>(MockBehavior.Strict); 
    mockPacket.Setup(p => p.GetBytes()).Returns(new byte[] { }).Verifiable(); 

    using (UdpCommsChannel udp = new UdpCommsChannel(mockClient.Object, It.IsAny<IPEndPoint>())) 
    { 
     udp.Open(); 
     udp.Send(mockPacket.Object); 
    } 

    mockPacket.Verify(p => p.GetBytes(), Times.Once()); 
} 

私のユニットテストは、次のようになります。

これ以上のコメントは歓迎します。

答えて

5

クラスの機能だけをテストする場合は、インターフェースICommunucatorを作成してから、UdpCommunicatorクラスを作成します.UdpCommunicatorは、チェックや条件なしにUdpClientのプロパティとメソッドを直接ラップします。

クラスでは、ラッパーを挿入し、tf UdpClientの代わりにisを使用します。

このように、テストでは、ISenderを模擬してテストすることができます。

もちろん、ラッパー自体のテストはありませんが、単なるコール転送の場合は、この必要はありません。

基本的には、正しい方向から始めましたが、カスタム論理を追加しました。この論理はテストできません。カスタムロジックとcomm部分を分割する必要があります。

すなわち、あなたのクラスは次のように次のようになります。

public MyClass(ICommunicator comm) 
{ 
    public void Method1(someparam) 
    { 
     //do some work with ICommunicator 
    } 
    .... 
} 

そして、あなたのテストは、次のようになります。コミュニケータのオープンが呼び出されたかどうかをチェックすることができますいくつか確認してくださいステートメントで、だから、

var mockComm = Mock.GetMock<ICommunicator>(); 
mockComm.Setup .... 
var myTestObj = new MyClass(mock.Object); 
MyClass.Method1(something); 

mock.Verify.... 

、適切なデータが渡された場合など

一般的に、システムやサードパーティのクラスをテストする必要はありません。

コードでこのようなクラスを使用している場合は、それらを注入可能にします。これらのクラスに仮想メソッドがない場合(つまり、直接モックすることはできません)、(SqlConnectionなどのように)IDbConnectionを実装するような共通インターフェイスを実装しない場合は、上記のようなプレーンラッパーを作成します。

テスト容易性の向上のほかに、このようなアプローチは、それははるかに簡単に将来的にあなたのコードを変更するようになります - つまり、あなたが通信のいくつかの他の方法を必要とするときは、など

+0

お返事をお寄せいただきありがとうございますが。あなたは "...あなたはICommunicatorを嘲笑することができます..."と言うことを意味しましたか? – Andy

+0

pls、編集 –

+0

を参照してくださいねえ、それは今感謝します、ありがとう。 – Andy

関連する問題