diff --git a/Directory.Build.props b/Directory.Build.props index 59ed3a3..83b1ab4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 0.3.3 + 0.3.4 \ No newline at end of file diff --git a/src/QAToolKit.Engine.HttpTester.Test/Exceptions/QAToolKitEngineHttpTesterExceptionTests.cs b/src/QAToolKit.Engine.HttpTester.Test/Exceptions/QAToolKitEngineHttpTesterExceptionTests.cs index 0fdd524..74247c9 100644 --- a/src/QAToolKit.Engine.HttpTester.Test/Exceptions/QAToolKitEngineHttpTesterExceptionTests.cs +++ b/src/QAToolKit.Engine.HttpTester.Test/Exceptions/QAToolKitEngineHttpTesterExceptionTests.cs @@ -1,6 +1,5 @@ using QAToolKit.Engine.HttpTester.Exceptions; using System; -using System.Runtime.Serialization; using Xunit; namespace QAToolKit.Engine.HttpTester.Test.Exceptions diff --git a/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs b/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs index 581f806..6919688 100644 --- a/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs +++ b/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs @@ -5,13 +5,11 @@ using System.Linq; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; -using System.Runtime.InteropServices; using System.Threading.Tasks; using Xunit; namespace QAToolKit.Engine.HttpTester.Test -{ +{ public class HttpTestAsserterTests { [Fact] @@ -120,7 +118,7 @@ public async Task HttpTestAsserterHeaderMissing_Fails() var httpDuration = client.HttpDuration; Assert.Throws(() => asserter .ResponseContentContains("scott") - .RequestDurationEquals(duration, (x) => x < 2000) + .RequestDurationEquals(duration, (x) => x < Convert.ToInt64("2000"), "x < 2000") .RequestDurationEquals(httpDuration, (x) => x < 1800) .ResponseStatusCodeEquals(HttpStatusCode.OK) .ResponseContentTypeEquals("application/json") diff --git a/src/QAToolKit.Engine.HttpTester/Exceptions/QAToolKitEngineHttpTesterException.cs b/src/QAToolKit.Engine.HttpTester/Exceptions/QAToolKitEngineHttpTesterException.cs index f050139..e3814ba 100644 --- a/src/QAToolKit.Engine.HttpTester/Exceptions/QAToolKitEngineHttpTesterException.cs +++ b/src/QAToolKit.Engine.HttpTester/Exceptions/QAToolKitEngineHttpTesterException.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; namespace QAToolKit.Engine.HttpTester.Exceptions { diff --git a/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs b/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs index 776ffb1..ec3aa55 100644 --- a/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs +++ b/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs @@ -3,6 +3,7 @@ using QAToolKit.Engine.HttpTester.Models; using System; using System.Collections.Generic; +using System.Linq.Expressions; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -24,7 +25,8 @@ public class HttpTestAsserter : IHttpTestAsserter /// public HttpTestAsserter(HttpResponseMessage httpResponseMessage) { - _httpResponseMessage = httpResponseMessage ?? throw new ArgumentNullException($"{nameof(httpResponseMessage)} is null."); + _httpResponseMessage = httpResponseMessage ?? + throw new ArgumentNullException($"{nameof(httpResponseMessage)} is null."); _assertResults = new List(); } @@ -40,8 +42,8 @@ public IEnumerable AssertAll() /// /// HTTP body contains a string (ignores case) /// - /// - /// + /// Check if the HTTP response body contains a keyword. + /// Use case sensitive string comparison. /// public IHttpTestAsserter ResponseContentContains(string keyword, bool caseInsensitive = true) { @@ -52,20 +54,27 @@ public IHttpTestAsserter ResponseContentContains(string keyword, bool caseInsens var bodyString = _httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - _assertResults.Add(new AssertResult() + var assertResult = new AssertResult() { - Name = nameof(ResponseContentContains), - Message = $"Body contains '{keyword}'.", - IsTrue = caseInsensitive ? StringHelper.ContainsCaseInsensitive(bodyString, keyword) : bodyString.Contains(keyword) - }); + Name = nameof(ResponseContentContains) + }; + + assertResult.IsTrue = caseInsensitive + ? StringHelper.ContainsCaseInsensitive(bodyString, keyword) + : bodyString.Contains(keyword); + assertResult.Message = assertResult.IsTrue + ? $"Response body contains keyword '{keyword}'." + : $"Response body does not contain keyword '{keyword}'."; + + _assertResults.Add(assertResult); return this; } - + /// /// Check if the response contains specified Content Type /// - /// + /// Check if the response content type equals the parameter. /// /// public IHttpTestAsserter ResponseContentTypeEquals(string contentType) @@ -75,12 +84,12 @@ public IHttpTestAsserter ResponseContentTypeEquals(string contentType) throw new ArgumentNullException($"{nameof(contentType)} is null."); } - var bodyString = _httpResponseMessage.Content.Headers.ContentType; - + var responseContentType = _httpResponseMessage.Content.Headers.ContentType.MediaType; + _assertResults.Add(new AssertResult() { Name = nameof(ResponseContentTypeEquals), - Message = $"Response content-type equals '{contentType}'.", + Message = $"Expected content-type = '{contentType}', actual = '{responseContentType}'.", IsTrue = _httpResponseMessage.Content.Headers.ContentType.MediaType == contentType }); @@ -90,18 +99,44 @@ public IHttpTestAsserter ResponseContentTypeEquals(string contentType) /// /// Verify request duration /// - /// - /// + /// Actual duration of the HTTP request execution + /// It's a function that validates the duration + /// String predicateFunctionExpression for the report. If set it will be used in the assert result message. /// - public IHttpTestAsserter RequestDurationEquals(long duration, Func predicateFunction) + public IHttpTestAsserter RequestDurationEquals(long duration, Expression> predicateFunction, string predicateFunctionExpression = null) { - var isTrue = predicateFunction.Invoke(duration); - _assertResults.Add(new AssertResult() + var isTrue = predicateFunction.Compile()(duration); + + var assertResult = new AssertResult() { Name = nameof(RequestDurationEquals), - Message = $"Duration is '{duration}'.", IsTrue = isTrue - }); + }; + + if (isTrue) + { + if (string.IsNullOrEmpty(predicateFunctionExpression)) + { + assertResult.Message = $"Duration is '{duration}ms' and is valid."; + } + else + { + assertResult.Message = $"Duration is '{duration}ms' and is valid with predicateFunctionExpression '{predicateFunctionExpression}'."; + } + } + else + { + if (string.IsNullOrEmpty(predicateFunctionExpression)) + { + assertResult.Message = $"Duration is '{duration}ms' and is invalid."; + } + else + { + assertResult.Message = $"Duration is '{duration}ms' and is invalid with predicateFunctionExpression '{predicateFunctionExpression}'."; + } + } + + _assertResults.Add(assertResult); return this; } @@ -109,7 +144,7 @@ public IHttpTestAsserter RequestDurationEquals(long duration, Func p /// /// HTTP response contains a header /// - /// + /// Check if the HTTP response contains the header with the name. /// public IHttpTestAsserter ResponseHasHttpHeader(string headerName) { @@ -118,12 +153,17 @@ public IHttpTestAsserter ResponseHasHttpHeader(string headerName) throw new ArgumentNullException($"{nameof(headerName)} is null."); } - _assertResults.Add(new AssertResult() + var assertResult = new AssertResult { Name = nameof(ResponseHasHttpHeader), - Message = $"Contains header '{headerName}'.", IsTrue = _httpResponseMessage.Headers.TryGetValues(headerName, out var values) - }); + }; + + assertResult.Message = assertResult.IsTrue + ? $"Response message contains header '{headerName}'." + : $"Response message does not contain header '{headerName}'."; + + _assertResults.Add(assertResult); return this; } @@ -131,14 +171,15 @@ public IHttpTestAsserter ResponseHasHttpHeader(string headerName) /// /// Verify if response code equals /// - /// + /// Check if the HTTP response status code equals to this parameter. /// public IHttpTestAsserter ResponseStatusCodeEquals(HttpStatusCode httpStatusCode) { _assertResults.Add(new AssertResult() { Name = nameof(ResponseStatusCodeEquals), - Message = $"Expected status code is '{httpStatusCode}' return code is '{_httpResponseMessage.StatusCode}'.", + Message = + $"Expected status code = '{httpStatusCode}', actual = '{_httpResponseMessage.StatusCode}'.", IsTrue = _httpResponseMessage.StatusCode == httpStatusCode }); @@ -154,7 +195,7 @@ public IHttpTestAsserter ResponseStatusCodeIsSuccess() _assertResults.Add(new AssertResult() { Name = nameof(ResponseStatusCodeIsSuccess), - Message = $"Expected status code is '2xx' return code is '{_httpResponseMessage.StatusCode}'.", + Message = $"Expected status code = '2xx', actual = '{_httpResponseMessage.StatusCode}'.", IsTrue = _httpResponseMessage.IsSuccessStatusCode }); @@ -172,11 +213,11 @@ public IHttpTestAsserter ResponseBodyIsEmpty() _assertResults.Add(new AssertResult() { Name = nameof(ResponseBodyIsEmpty), - Message = $"Expected empty body, returned body is '{bodyString}'.", + Message = $"Expected empty response body, actual = '{bodyString}'.", IsTrue = string.IsNullOrEmpty(bodyString) }); return this; } } -} +} \ No newline at end of file diff --git a/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTestAsserter.cs b/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTestAsserter.cs index d621001..e9e1446 100644 --- a/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTestAsserter.cs +++ b/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTestAsserter.cs @@ -1,6 +1,7 @@ using QAToolKit.Engine.HttpTester.Models; using System; using System.Collections.Generic; +using System.Linq.Expressions; using System.Net; using System.Net.Http.Headers; @@ -18,13 +19,15 @@ public interface IHttpTestAsserter /// /// IHttpTestAsserter ResponseContentContains(string keyword, bool caseInsensitive = true); + /// /// Verify request duration /// /// /// + /// /// - IHttpTestAsserter RequestDurationEquals(long duration, Func predicateFunction); + IHttpTestAsserter RequestDurationEquals(long duration, Expression> predicateFunction, string predicateFunctionExpression = null); /// /// Verify if response code equals ///