From 26392cdd2028eff2132948d5cc5e36e08a2d69a9 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 11 Aug 2019 15:34:59 +0800 Subject: Add FluentAssertions. --- .../Helpers/AssertionResponseExtensions.cs | 114 +++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Timeline.Tests/Helpers/AssertionResponseExtensions.cs (limited to 'Timeline.Tests/Helpers/AssertionResponseExtensions.cs') diff --git a/Timeline.Tests/Helpers/AssertionResponseExtensions.cs b/Timeline.Tests/Helpers/AssertionResponseExtensions.cs new file mode 100644 index 00000000..b56340ea --- /dev/null +++ b/Timeline.Tests/Helpers/AssertionResponseExtensions.cs @@ -0,0 +1,114 @@ +using FluentAssertions; +using FluentAssertions.Execution; +using FluentAssertions.Primitives; +using Newtonsoft.Json; +using System; +using System.Net; +using System.Net.Http; +using Timeline.Models.Http; + +namespace Timeline.Tests.Helpers +{ + public class HttpResponseMessageAssertions + : ReferenceTypeAssertions + { + public HttpResponseMessageAssertions(HttpResponseMessage instance) + { + Subject = instance; + } + + protected override string Identifier => "HttpResponseMessage"; + + public AndConstraint HaveStatusCode(HttpStatusCode expected, string because = "", params object[] becauseArgs) + { + Execute.Assertion.BecauseOf(because, becauseArgs) + .ForCondition(Subject.StatusCode == expected) + .FailWith("Expected status code is {}, but found {}.", expected, Subject.StatusCode); + return new AndConstraint(Subject); + } + + public AndWhichConstraint HaveBodyAsJson(string because = "", params object[] becauseArgs) + { + var a = Execute.Assertion.BecauseOf(because, becauseArgs); + string body; + try + { + body = Subject.Content.ReadAsStringAsync().Result; + } + catch (Exception e) + { + a.FailWith("Failed to read response body. Exception is {}.", e); + return new AndWhichConstraint(Subject, null); + } + + try + { + var result = JsonConvert.DeserializeObject(body); + return new AndWhichConstraint(Subject, result); + } + catch (Exception e) + { + a.FailWith("Failed to convert response body to {}. Exception is {}.", typeof(T).FullName, e); + return new AndWhichConstraint(Subject, null); + } + } + } + + public static class AssertionResponseExtensions + { + public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance) + { + return new HttpResponseMessageAssertions(instance); + } + + public static AndConstraint HaveStatusCodeOk(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveStatusCode(HttpStatusCode.OK, because, becauseArgs); + } + + public static AndConstraint HaveStatusCodeCreated(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveStatusCode(HttpStatusCode.Created, because, becauseArgs); + } + + public static AndConstraint HaveStatusCodeBadRequest(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveStatusCode(HttpStatusCode.BadRequest, because, becauseArgs); + } + + public static AndConstraint HaveStatusCodeNotFound(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveStatusCode(HttpStatusCode.NotFound, because, becauseArgs); + } + + public static AndWhichConstraint HaveBodyAsCommonResponse(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveBodyAsJson(because, becauseArgs); + } + + public static void HaveBodyAsCommonResponseWithCode(this HttpResponseMessageAssertions assertions, int expected, string because = "", params object[] becauseArgs) + { + assertions.HaveBodyAsCommonResponse(because, becauseArgs).Which.Code.Should().Be(expected, because, becauseArgs); + } + + public static void BePutCreated(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + assertions.HaveStatusCodeCreated(because, becauseArgs).And.Should().HaveBodyAsCommonResponse(because, becauseArgs).Which.Should().BeEquivalentTo(CommonPutResponse.Created, because, becauseArgs); + } + + public static void BePutModified(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + assertions.HaveStatusCodeOk(because, becauseArgs).And.Should().HaveBodyAsCommonResponse(because, becauseArgs).Which.Should().BeEquivalentTo(CommonPutResponse.Modified, because, becauseArgs); + } + + public static void BeDeleteDeleted(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + assertions.HaveStatusCodeOk(because, becauseArgs).And.Should().HaveBodyAsCommonResponse(because, becauseArgs).Which.Should().BeEquivalentTo(CommonDeleteResponse.Deleted, because, becauseArgs); + } + + public static void BeDeleteNotExist(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + assertions.HaveStatusCodeOk(because, becauseArgs).And.Should().HaveBodyAsCommonResponse(because, becauseArgs).Which.Should().BeEquivalentTo(CommonDeleteResponse.NotExists, because, becauseArgs); + } + } +} -- cgit v1.2.3 From 4b0d4ba4e79c1a2e22ccf131d1abdbf113d78b6a Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 11 Aug 2019 16:08:38 +0800 Subject: Fix the bug in assert message and add a formatter. --- .../Helpers/AssertionResponseExtensions.cs | 31 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'Timeline.Tests/Helpers/AssertionResponseExtensions.cs') diff --git a/Timeline.Tests/Helpers/AssertionResponseExtensions.cs b/Timeline.Tests/Helpers/AssertionResponseExtensions.cs index b56340ea..38617b92 100644 --- a/Timeline.Tests/Helpers/AssertionResponseExtensions.cs +++ b/Timeline.Tests/Helpers/AssertionResponseExtensions.cs @@ -1,5 +1,6 @@ using FluentAssertions; using FluentAssertions.Execution; +using FluentAssertions.Formatting; using FluentAssertions.Primitives; using Newtonsoft.Json; using System; @@ -9,9 +10,31 @@ using Timeline.Models.Http; namespace Timeline.Tests.Helpers { + public class HttpResponseMessageValueFormatter : IValueFormatter + { + public bool CanHandle(object value) + { + return value is HttpResponseMessage; + } + + public string Format(object value, FormattingContext context, FormatChild formatChild) + { + string newline = context.UseLineBreaks ? Environment.NewLine : ""; + string padding = new string('\t', context.Depth); + + var res = (HttpResponseMessage)value; + return $"{newline}{padding} Status Code: {res.StatusCode} ; Body: {res.Content.ReadAsStringAsync().Result} ;"; + } + } + public class HttpResponseMessageAssertions - : ReferenceTypeAssertions + : ReferenceTypeAssertions { + static HttpResponseMessageAssertions() + { + Formatter.AddFormatter(new HttpResponseMessageValueFormatter()); + } + public HttpResponseMessageAssertions(HttpResponseMessage instance) { Subject = instance; @@ -23,7 +46,7 @@ namespace Timeline.Tests.Helpers { Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.StatusCode == expected) - .FailWith("Expected status code is {}, but found {}.", expected, Subject.StatusCode); + .FailWith("Expected status code of {context:HttpResponseMessage} to be {0}{reason}, but found {1}.\nResponse is {2}.", expected, Subject.StatusCode, Subject); return new AndConstraint(Subject); } @@ -37,7 +60,7 @@ namespace Timeline.Tests.Helpers } catch (Exception e) { - a.FailWith("Failed to read response body. Exception is {}.", e); + a.FailWith("Failed to read response body of {context:HttpResponseMessage}{reason}.\nException is {0}.", e); return new AndWhichConstraint(Subject, null); } @@ -48,7 +71,7 @@ namespace Timeline.Tests.Helpers } catch (Exception e) { - a.FailWith("Failed to convert response body to {}. Exception is {}.", typeof(T).FullName, e); + a.FailWith("Failed to convert response body of {context:HttpResponseMessage} to {0}{reason}.\nResponse is {1}.\nException is {2}.", typeof(T).FullName, Subject, e); return new AndWhichConstraint(Subject, null); } } -- cgit v1.2.3