From cb47c2e07066bf3ed6931274d36c34e484414613 Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Fri, 6 Oct 2023 11:34:08 -0700 Subject: [PATCH 1/2] Fixing Chap 20 flaky tests This has the side benefit of also removing WebClient. Need to review book content to see if there would need to be chapter changes to go with this. --- src/Chapter20.Tests/BaseProgramTests.cs | 97 ++++--------------- src/Chapter20.Tests/Listing20.01.Tests.cs | 1 + src/Chapter20.Tests/Listing20.02.Tests.cs | 1 + src/Chapter20.Tests/Listing20.03.Tests.cs | 2 + ...g20.01.SynchronousWebRequestHighLatency.cs | 4 +- .../Listing20.02.AsynchronousWebRequest.cs | 4 +- ...usHighLatencyUsingTaskAsynchronyPattern.cs | 5 +- 7 files changed, 29 insertions(+), 85 deletions(-) diff --git a/src/Chapter20.Tests/BaseProgramTests.cs b/src/Chapter20.Tests/BaseProgramTests.cs index a97d35660..dd2cadcae 100644 --- a/src/Chapter20.Tests/BaseProgramTests.cs +++ b/src/Chapter20.Tests/BaseProgramTests.cs @@ -7,17 +7,17 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Tests; -abstract public class BaseProgramTests +public abstract class BaseProgramTests { [NotNull] - static public ProgramWrapper? ProgramWrapper { get; set; } + public static ProgramWrapper? ProgramWrapper { get; set; } protected abstract string DefaultUrl { get; } [NotNull] public TestContext? TestContext { get; set; } - [TestInitializeAttribute] + [TestInitialize] public void TestInitialize() { Assert.IsNotNull(TestContext); @@ -29,7 +29,7 @@ public void TestInitialize() [TestMethod] [DataRow("IntelliTect", @"[1-9]\d*")] [DataRow("Text Snippet That Does Not Exist On The Page", @"0")] - public void Main_FindText_VerifyOccurenceCount(string findText, string countPattern) + public void Main_FindText_VerifyOccurrenceCount(string findText, string countPattern) { string url = DefaultUrl; string expected = @@ -41,10 +41,7 @@ public void Main_FindText_VerifyOccurenceCount(string findText, string countPatt Regex.Escape(url) }'\.\s+"; string actual = IntelliTect.TestTools.Console.ConsoleAssert.Execute("", - () => - { - ProgramWrapper.Main(new string[] { findText }).Wait(); - }); + () => ProgramWrapper.Main(new string[] { findText }).Wait()); Regex regex = new(expected); Assert.IsTrue(regex.Match(actual).Success, @@ -110,78 +107,22 @@ protected static void AssertAggregateExceptionType(string messagePrefix, Aggrega }); } - [TestMethod] - [ExpectedException(typeof(System.ArgumentNullException))] - public async Task Main_GivenNullUri_ThrowException() - { - try - { - await ProgramWrapper.Main(new string[] { "irrelevant", null! }); - Assert.Fail("Expected exception was not thrown."); - } - catch (AggregateException exception) - { - if (exception.InnerExceptions.Count != 1) - { - throw new InvalidOperationException("Unexpected scenario with there being more than one inner exception."); - } - exception.Handle(innerException => - { - // Rethrowing rather than using - // if condition on the type - ExceptionDispatchInfo.Capture( - innerException!).Throw(); - - return true; - }); - } - } + protected static HttpClient GetMockedHttpClient() + => new HttpClient(new MockHttpClientHandler()); +} - [TestMethod] - [DataRow("Bad Uri", "Could not find file *")] - [DataRow("https://bad uri", "The filename, directory name, or volume label syntax is incorrect. *", "Could not find a part of the path*", "Could not find a part of the path*")] - [DataRow("https://thisisanotherbadurlthatpresumablyldoesnotexist.notexist", "No such host is known.*", "nodename nor servname provided, or not known*", "Name or service not known*")] - [ExpectedException(typeof(WebException))] - public async Task Main_GivenBadUri_ThrowException(string uri, string defaultMessagePrefix, string? messagePrefixOSX = null, string? messagePrefixLinux = null) +file class MockHttpClientHandler : HttpMessageHandler +{ + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - messagePrefixOSX ??= defaultMessagePrefix; - messagePrefixLinux ??= defaultMessagePrefix; - - try - { - await ProgramWrapper.Main(new string[] { "irrelevant", uri }); - Assert.Fail("Expected exception was not thrown."); - } - catch (Exception exception) + HttpResponseMessage response = new(HttpStatusCode.OK) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - AssertMainException(defaultMessagePrefix, exception); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - AssertMainException(messagePrefixOSX, exception); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - AssertMainException(messagePrefixLinux, exception); - } - if (exception is AggregateException aggregateException) - { - // InnerException expected to be WebException. - exception = aggregateException.Flatten(); - aggregateException.Handle(innerException => - { - // Rethrowing rather than using - // if condition on the type - ExceptionDispatchInfo.Capture( - innerException) - .Throw(); - return true; - }); - } - // WebException expected - else throw; - } + Content = new StringContent($""" + Test Data From {GetType().Namespace}.{nameof(MockHttpClientHandler)} + Request Uri: {request.RequestUri}, + The tests search for the word "IntelliTect" so that is can count the number of times it appears on the page. + """) + }; + return Task.FromResult(response); } } diff --git a/src/Chapter20.Tests/Listing20.01.Tests.cs b/src/Chapter20.Tests/Listing20.01.Tests.cs index b7d41bda8..71fa08666 100644 --- a/src/Chapter20.Tests/Listing20.01.Tests.cs +++ b/src/Chapter20.Tests/Listing20.01.Tests.cs @@ -9,6 +9,7 @@ public class ProgramTests : BaseProgramTests [ClassInitialize] static public void ClassInitialize(TestContext _) { + Program.HttpClient = GetMockedHttpClient(); ProgramWrapper = new ProgramWrapper( (args) => Task.Run(() => Program.Main(args))); diff --git a/src/Chapter20.Tests/Listing20.02.Tests.cs b/src/Chapter20.Tests/Listing20.02.Tests.cs index 580df5444..c4bfc31ca 100644 --- a/src/Chapter20.Tests/Listing20.02.Tests.cs +++ b/src/Chapter20.Tests/Listing20.02.Tests.cs @@ -9,6 +9,7 @@ public class ProgramTests : BaseProgramTests [ClassInitialize] public static void ClassInitialize(TestContext _) { + Program.HttpClient = GetMockedHttpClient(); ProgramWrapper = new ProgramWrapper( (args) => Task.Run(() => Program.Main(args))); diff --git a/src/Chapter20.Tests/Listing20.03.Tests.cs b/src/Chapter20.Tests/Listing20.03.Tests.cs index 624441c81..bb085a9f0 100644 --- a/src/Chapter20.Tests/Listing20.03.Tests.cs +++ b/src/Chapter20.Tests/Listing20.03.Tests.cs @@ -9,11 +9,13 @@ public class ProgramTests : BaseProgramTests [ClassInitialize] public static void ClassInitialize(TestContext _) { + Program.HttpClient = GetMockedHttpClient(); ProgramWrapper = new ProgramWrapper( (args) => Task.Run(() => Program.Main(args))); } + protected override void AssertMainException(string messagePrefix,Exception exception) { AssertMainException(messagePrefix, (AggregateException)exception); diff --git a/src/Chapter20/Listing20.01.SynchronousWebRequestHighLatency.cs b/src/Chapter20/Listing20.01.SynchronousWebRequestHighLatency.cs index 786fb1f81..f17676e95 100644 --- a/src/Chapter20/Listing20.01.SynchronousWebRequestHighLatency.cs +++ b/src/Chapter20/Listing20.01.SynchronousWebRequestHighLatency.cs @@ -7,6 +7,7 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_01; public static class Program { + public static HttpClient HttpClient { get; set; } = new(); public const string DefaultUrl = "https://IntelliTect.com"; public static void Main(string[] args) @@ -28,9 +29,8 @@ public static void Main(string[] args) $"Searching for '{findText}' at URL '{url}'."); Console.WriteLine("Downloading..."); - using WebClient webClient = new(); byte[] downloadData = - webClient.DownloadData(url); + HttpClient.GetByteArrayAsync(url).Result; Console.WriteLine("Searching..."); int textOccurrenceCount = CountOccurrences( diff --git a/src/Chapter20/Listing20.02.AsynchronousWebRequest.cs b/src/Chapter20/Listing20.02.AsynchronousWebRequest.cs index 432cffe2c..6ec176246 100644 --- a/src/Chapter20/Listing20.02.AsynchronousWebRequest.cs +++ b/src/Chapter20/Listing20.02.AsynchronousWebRequest.cs @@ -9,6 +9,7 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_02; public static class Program { + public static HttpClient HttpClient { get; set; } = new(); public const string DefaultUrl = "https://IntelliTect.com"; public static void Main(string[] args) @@ -29,9 +30,8 @@ public static void Main(string[] args) Console.WriteLine( $"Searching for '{findText}' at URL '{url}'."); - using WebClient webClient = new(); Console.Write("Downloading..."); - Task task = webClient.DownloadDataTaskAsync(url) + Task task = HttpClient.GetByteArrayAsync(url) .ContinueWith(antecedent => { byte[] downloadData = antecedent.Result; diff --git a/src/Chapter20/Listing20.03.AsynchronousHighLatencyUsingTaskAsynchronyPattern.cs b/src/Chapter20/Listing20.03.AsynchronousHighLatencyUsingTaskAsynchronyPattern.cs index fc9eb864a..d0df717f3 100644 --- a/src/Chapter20/Listing20.03.AsynchronousHighLatencyUsingTaskAsynchronyPattern.cs +++ b/src/Chapter20/Listing20.03.AsynchronousHighLatencyUsingTaskAsynchronyPattern.cs @@ -3,11 +3,11 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_03; #region INCLUDE using System; using System.IO; -using System.Net; using System.Threading.Tasks; public static class Program { + public static HttpClient HttpClient { get; set; } = new(); public const string DefaultUrl = "https://IntelliTect.com"; public static async Task Main(string[] args) @@ -28,9 +28,8 @@ public static async Task Main(string[] args) Console.WriteLine( $"Searching for '{findText}' at URL '{url}'."); - using WebClient webClient = new(); Task taskDownload = - webClient.DownloadDataTaskAsync(url); + HttpClient.GetByteArrayAsync(url); Console.Write("Downloading..."); while (!taskDownload.Wait(100)) From ff5f45576050d18657e7bd7e54e48d228bb8f9f9 Mon Sep 17 00:00:00 2001 From: Benjamin Michaelis Date: Sat, 7 Oct 2023 11:39:53 +0000 Subject: [PATCH 2/2] Update Listing20.03.Tests.cs --- src/Chapter20.Tests/Listing20.03.Tests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Chapter20.Tests/Listing20.03.Tests.cs b/src/Chapter20.Tests/Listing20.03.Tests.cs index bb085a9f0..1934faf2e 100644 --- a/src/Chapter20.Tests/Listing20.03.Tests.cs +++ b/src/Chapter20.Tests/Listing20.03.Tests.cs @@ -15,7 +15,6 @@ public static void ClassInitialize(TestContext _) Task.Run(() => Program.Main(args))); } - protected override void AssertMainException(string messagePrefix,Exception exception) { AssertMainException(messagePrefix, (AggregateException)exception);