Estoy trabajando en una clase que utiliza un UdpClient, y tratando de aprender/utilizar un enfoque TDD usando NUnit y Moq en el proceso.Mock UdpClient para prueba de unidad
Una parte escueto de mi clase hasta el momento es el siguiente:
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);
}
}
.
.
Para el método de envío, que tienen la siguiente prueba de la unidad en la actualidad
[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());
}
.
.
No estoy muy contento con eso porque está usando una dirección IP real, aunque solo sea el localhost, y el UdpClient dentro de la clase está físicamente enviándole datos. Por lo tanto, esta no es una verdadera prueba unitaria por lo que yo entiendo.
El problema es que no entiendo exactamente qué hacer al respecto. ¿Debo cambiar mi clase y pasar un nuevo UdpClient como una dependencia tal vez? ¿Se burla de la IPAddress de alguna manera?
Luchando un poco, así que tengo que parar aquí para ver si estoy en el camino correcto antes de continuar. Cualquier consejo apreciado!
(utilizando NUnit 2.5.7, Moq 4.0 y C# WinForms) .
.
ACTUALIZACIÓN:
OK, he rediseñado mi código de la siguiente manera:
Creado una interfaz IUdpClient:
public interface IUdpClient
{
void Connect(IPEndPoint endpoint);
int Send(byte[] data, int num);
void Close();
}
.
creado una clase adaptador para envolver la clase sistema de 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
}
.
refactorizado mis clas UdpCommsChannel para requerir una instancia de un IUdpClient inyectado por el constructor:
public UdpCommsChannel(IUdpClient client, IPEndPoint endpoint)
{
this._udpClient = client;
this._endPoint = endpoint;
}
.
Mi prueba de la unidad ahora se ve así:
[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());
}
.
Cualquier comentario adicional es bienvenido.
Gracias por su respuesta. ¿Querías decir "... puedes burlarte de ICommunicator ..."? – Andy
pls, ver la edición –
Sí, eso tiene más sentido ahora, gracias. – Andy