运行 在使用 XUnit 的测试中
Running in Test using XUnit
第一次尝试学习测试驱动设计。我有一个这样的服务器:
public class ServerEngine
{
private static Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static List<Socket> _clientSockets = new List<Socket>();
private static byte[] _buffer = new byte[1024];
public ServerEngine()
{
SetupServer();
}
private void SetupServer()
{
Console.WriteLine("Setting up the server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
// Settingup the backlog
_serverSocket.Listen(1);
//Listen for connections
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void AcceptCallback(IAsyncResult ar)
{
// Add the accepted socket to the list of sockets
Socket socket = _serverSocket.EndAccept(ar);
_clientSockets.Add(socket);
Console.WriteLine("A client has connected");
// listen for messages coming from the new accepted socket
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
// Start accepting a new connection again
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void ReceiveCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
try
{
var received = socket.EndReceive(ar);
var dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
var text = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine($"Text Received: {text}");
var response = AddToHashSet(text);
var data = Encoding.ASCII.GetBytes(response.ToString());
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
catch (SocketException)
{
socket.Close();
Console.WriteLine("A client has disconnected.");
}
}
private void SendCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
private HashSet<TidContainerModel> _tidContainerModels = new HashSet<TidContainerModel>(new TidContainerModelComparer());
private bool AddToHashSet(string value)
{
var tcv = new TidContainerModel
{
Tid = value,
TimeAdded = DateTime.Now,
Type = 'R',
Rssi = -444
};
return _tidContainerModels.Add(tcv);
}
}
我在 Program Main 中调用它来设置服务器。然后我像这样创建了一个 xUnit 测试:
private Socket _clentSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private ServerEngine serverEngine = new ServerEngine();
[Fact]
public void ConnectToServerTest()
{
// Arrange
bool expected = true;
// Act
bool actual = LoopConnect();
// Assert
Assert.Equal(expected, actual);
}
private bool LoopConnect()
{
int attempts = 0;
var connected = false;
while (!_clentSocket.Connected)
{
try
{
attempts++;
var ipAddress = new IPEndPoint(IPAddress.Parse("172.16.35.71"), 100);
_clentSocket.Connect(ipAddress);
}
catch (SocketException se)
{
Console.Clear();
Console.WriteLine($"Failed connecting {se.Message}. Reconnecting attempt {attempts}");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
connected = true;
Console.Clear();
Console.WriteLine("Connected to the server");
return connected;
}
在不使用测试的情况下,该程序运行良好。但是当我使用测试时,我失败了,错误为:
Server.Test.ServerEngineTest.ConnectToServerTest
Source: ServerEngineTest.cs line 15
Duration: 209 ms
Message:
System.IO.IOException : The handle is invalid.
Stack Trace:
__Error.WinIOError(Int32 errorCode, String maybeFullPath)
Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
Console.Clear()
ServerEngineTest.LoopConnect() line 51
ServerEngineTest.ConnectToServerTest() line 21
如果我使用控制台应用程序连接到服务器,它工作得很好。我想学习如何在这个项目中使用 xUnit。
看看你的堆栈跟踪,它告诉你问题所在:
Stack Trace:
__Error.WinIOError(Int32 errorCode, String maybeFullPath)
Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
Console.Clear()
ServerEngineTest.LoopConnect() line 51
ServerEngineTest.ConnectToServerTest() line 21
基本上,您正在尝试清除控制台,但您的测试中没有分配任何控制台。这是你永远不应该做的事情,原因有两个:
- 你应该嘲笑你的 I/O 才能测试它。
- 绝对不要将这种控制台 I/O 与套接字服务混合使用,无论它做什么。使用依赖注入来提取和包含控制台 I/O(或者更好的是,适当的日志记录接口)与启动和维护 TCP 服务器的实际工作分开。
第一次尝试学习测试驱动设计。我有一个这样的服务器:
public class ServerEngine
{
private static Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static List<Socket> _clientSockets = new List<Socket>();
private static byte[] _buffer = new byte[1024];
public ServerEngine()
{
SetupServer();
}
private void SetupServer()
{
Console.WriteLine("Setting up the server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
// Settingup the backlog
_serverSocket.Listen(1);
//Listen for connections
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void AcceptCallback(IAsyncResult ar)
{
// Add the accepted socket to the list of sockets
Socket socket = _serverSocket.EndAccept(ar);
_clientSockets.Add(socket);
Console.WriteLine("A client has connected");
// listen for messages coming from the new accepted socket
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
// Start accepting a new connection again
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void ReceiveCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
try
{
var received = socket.EndReceive(ar);
var dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
var text = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine($"Text Received: {text}");
var response = AddToHashSet(text);
var data = Encoding.ASCII.GetBytes(response.ToString());
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
catch (SocketException)
{
socket.Close();
Console.WriteLine("A client has disconnected.");
}
}
private void SendCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
private HashSet<TidContainerModel> _tidContainerModels = new HashSet<TidContainerModel>(new TidContainerModelComparer());
private bool AddToHashSet(string value)
{
var tcv = new TidContainerModel
{
Tid = value,
TimeAdded = DateTime.Now,
Type = 'R',
Rssi = -444
};
return _tidContainerModels.Add(tcv);
}
}
我在 Program Main 中调用它来设置服务器。然后我像这样创建了一个 xUnit 测试:
private Socket _clentSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private ServerEngine serverEngine = new ServerEngine();
[Fact]
public void ConnectToServerTest()
{
// Arrange
bool expected = true;
// Act
bool actual = LoopConnect();
// Assert
Assert.Equal(expected, actual);
}
private bool LoopConnect()
{
int attempts = 0;
var connected = false;
while (!_clentSocket.Connected)
{
try
{
attempts++;
var ipAddress = new IPEndPoint(IPAddress.Parse("172.16.35.71"), 100);
_clentSocket.Connect(ipAddress);
}
catch (SocketException se)
{
Console.Clear();
Console.WriteLine($"Failed connecting {se.Message}. Reconnecting attempt {attempts}");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
connected = true;
Console.Clear();
Console.WriteLine("Connected to the server");
return connected;
}
在不使用测试的情况下,该程序运行良好。但是当我使用测试时,我失败了,错误为:
Server.Test.ServerEngineTest.ConnectToServerTest
Source: ServerEngineTest.cs line 15
Duration: 209 ms
Message:
System.IO.IOException : The handle is invalid.
Stack Trace:
__Error.WinIOError(Int32 errorCode, String maybeFullPath)
Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
Console.Clear()
ServerEngineTest.LoopConnect() line 51
ServerEngineTest.ConnectToServerTest() line 21
如果我使用控制台应用程序连接到服务器,它工作得很好。我想学习如何在这个项目中使用 xUnit。
看看你的堆栈跟踪,它告诉你问题所在:
Stack Trace:
__Error.WinIOError(Int32 errorCode, String maybeFullPath)
Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
Console.Clear()
ServerEngineTest.LoopConnect() line 51
ServerEngineTest.ConnectToServerTest() line 21
基本上,您正在尝试清除控制台,但您的测试中没有分配任何控制台。这是你永远不应该做的事情,原因有两个:
- 你应该嘲笑你的 I/O 才能测试它。
- 绝对不要将这种控制台 I/O 与套接字服务混合使用,无论它做什么。使用依赖注入来提取和包含控制台 I/O(或者更好的是,适当的日志记录接口)与启动和维护 TCP 服务器的实际工作分开。