Mock UdpClient для модульного тестирования

Я работаю над классом, который использует UdpClient, и пытаюсь изучить / использовать подход TDD, используя в процессе NUnit и Moq.

Самая простая часть моего класса пока выглядит следующим образом:

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-адрес, хотя и только localhost, а UdpClient внутри класса физически отправляет ему данные. Поэтому, насколько я понимаю, это не настоящий модульный тест.

Проблема в том, что я не могу понять, что именно с этим делать. Должен ли я изменить свой класс и, возможно, передать новый UdpClient в качестве зависимости? Как-нибудь издеваться над IPAddress?

Немного борется, поэтому мне нужно остановиться здесь, чтобы посмотреть, на правильном ли я пути, прежде чем продолжить. Любые советы приветствуются!

(Использование NUnit 2.5.7, Moq 4.0 и C # WinForms.) .
.

ОБНОВЛЕНИЕ:

Хорошо, я реорганизовал свой код следующим образом:

Создан интерфейс IUdpClient:

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

.

Создан класс адаптера для обертывания системного класса UdpClient:

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
}

.

Реорганизован мой класс UdpCommsChannel, чтобы он требовал экземпляра 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());
}

.

Любые дальнейшие комментарии приветствуются.

6
задан Andy 24 July 2011 в 08:53
поделиться