I would like to unit test the WpaConnection class which contains multiple continuous tasks. Starting of these task is dependent on TCP connection. I would like to gather some information on what would be the best way to unit test the class and want to know how I can mock the TCP client so that ConnectAsync line is skipped.
using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;using System.Threading.Tasks;namespace WpaConnection{ public class WpaConnection : IDisposable { private readonly IPEndPoint _wapIpEndPoint; private readonly TcpClient _tcpClient = new TcpClient(); private readonly Task _connectTask; private bool _isExiting; public WpaConnection( IPEndPoint wapIpEndPoint, CancellationToken stoppingToken) { _wapIpEndPoint = wapIpEndPoint; _connectTask = ConnectTask(wapIpEndPoint, stoppingToken); _isExiting = false; } public event EventHandler<WapReadEventArgs> OnRead; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Disconnect() { if (!_connectTask.IsCompleted) { _isExiting = true; } } protected virtual void Dispose(bool disposing) { if (disposing) { _tcpClient.Dispose(); } } private async Task ConnectTask(IPEndPoint wapIpEndPoint, CancellationToken stoppingToken) { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); Task readEventAsyncTask; Task task1; Task task2; Task task3; Console.WriteLine("WpaConnection: ConnectTask started"); try { await _tcpClient.ConnectAsync(wapIpEndPoint.Address, wapIpEndPoint.Port); Console.WriteLine("WpaConnection: ConnectTask Connected to {WapEndPoint}", wapIpEndPoint); readEventAsyncTask = ReadEventTask(cancellationTokenSource.Token); task1 = Task1(cancellationTokenSource.Token); task2 = Task2(cancellationTokenSource.Token); task3 = Task3(cancellationTokenSource.Token); while (!stoppingToken.IsCancellationRequested && _tcpClient.Connected && !_isExiting) { await Task.Delay(1, stoppingToken); } _tcpClient.Close(); Console.WriteLine("WpaConnection: ConnectTask closed TcpClient"); } catch (Exception) { _isExiting = true; } cancellationTokenSource.Cancel(); Console.WriteLine("WpaConnection: ConnectTask exiting..."); } private async Task Task3(CancellationToken stoppingToken) { Console.WriteLine("WpaConnection: Task3 started"); try { int sequence = 0; while (!stoppingToken.IsCancellationRequested && !_isExiting) { Console.WriteLine($"Task3 {sequence++}"); await Task.Delay(1000, stoppingToken); } } catch (Exception) { _isExiting = true; } Console.WriteLine("WpaConnection: Task3 exiting..."); } private async Task Task1(CancellationToken stoppingToken) { Console.WriteLine("WpaConnection: Task1 started"); try { int sequence = 0; while (!stoppingToken.IsCancellationRequested && !_isExiting) { Console.WriteLine($"Task1 {sequence++}"); await Task.Delay(1000, stoppingToken); } } catch (Exception) { _isExiting = true; } Console.WriteLine("WpaConnection: Task1 exiting..."); } private async Task Task2(CancellationToken stoppingToken) { Console.WriteLine("WpaConnection: Task2 started"); try { int sequence = 0; while (!stoppingToken.IsCancellationRequested && !_isExiting) { Console.WriteLine($"Task2 {sequence++}"); await Task.Delay(1000, stoppingToken); } } catch (Exception) { _isExiting = true; } Console.WriteLine("WpaConnection: Task2 exiting..."); } private async Task ReadEventTask(CancellationToken stoppingToken) { Console.WriteLine("WpaConnection: ReadEventTask started"); byte[] buffer = new byte[512]; try { while (!stoppingToken.IsCancellationRequested && !_isExiting && _tcpClient.Connected) { int length = await _tcpClient.GetStream().ReadAsync(buffer, 0, buffer.Length, stoppingToken); if (length > 0) { byte[] data = new byte[length]; Buffer.BlockCopy(buffer, 0, data, 0, length); OnRead?.Invoke( this, new WapReadEventArgs() { WapEndPoint = _wapIpEndPoint, Length = length, Buffer = data, }); } } } catch (Exception) { _isExiting = true; } Console.WriteLine("WpaConnection: ReadEventTask exiting..."); } } public class WapReadEventArgs : EventArgs { public IPEndPoint WapEndPoint { get; set; } public int Length { get; set; } public byte[] Buffer { get; set; } } internal class Program { static void Main(string[] args) { IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Any, 1234); CancellationTokenSource cancellationToken = new CancellationTokenSource(); WpaConnection connection = new WpaConnection(iPEndPoint, cancellationToken.Token); Task.Delay(1000).Wait(); cancellationToken.Cancel(); Console.ReadLine(); } }}
Learning the best way of testing such classes.