From 4d15f7d696825f332884bb23e67760d6d1f5a736 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 11 Aug 2019 15:34:59 +0800 Subject: Add FluentAssertions. --- Timeline.Tests/AuthorizationUnitTest.cs | 13 +-- .../Helpers/AssertionResponseExtensions.cs | 114 +++++++++++++++++++++ .../Authentication/AuthenticationExtensions.cs | 2 +- Timeline.Tests/Helpers/InvalidModelTestHelpers.cs | 12 +-- Timeline.Tests/Helpers/ResponseExtensions.cs | 61 ----------- Timeline.Tests/Helpers/UserInfoComparers.cs | 47 --------- Timeline.Tests/Mock/Data/TestUsers.cs | 4 +- Timeline.Tests/Timeline.Tests.csproj | 1 + Timeline.Tests/TokenUnitTest.cs | 45 ++++---- Timeline.Tests/UserUnitTest.cs | 52 ++++------ 10 files changed, 171 insertions(+), 180 deletions(-) create mode 100644 Timeline.Tests/Helpers/AssertionResponseExtensions.cs delete mode 100644 Timeline.Tests/Helpers/ResponseExtensions.cs delete mode 100644 Timeline.Tests/Helpers/UserInfoComparers.cs (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/AuthorizationUnitTest.cs b/Timeline.Tests/AuthorizationUnitTest.cs index d9fb7406..3df4d0fd 100644 --- a/Timeline.Tests/AuthorizationUnitTest.cs +++ b/Timeline.Tests/AuthorizationUnitTest.cs @@ -5,6 +5,7 @@ using Timeline.Tests.Helpers; using Timeline.Tests.Helpers.Authentication; using Xunit; using Xunit.Abstractions; +using FluentAssertions; namespace Timeline.Tests { @@ -27,7 +28,7 @@ namespace Timeline.Tests using (var client = _factory.CreateDefaultClient()) { var response = await client.GetAsync(AuthorizeUrl); - Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + response.Should().HaveStatusCode(HttpStatusCode.Unauthorized); } } @@ -37,7 +38,7 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsUser()) { var response = await client.GetAsync(AuthorizeUrl); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); + response.Should().HaveStatusCode(HttpStatusCode.OK); } } @@ -47,9 +48,9 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsUser()) { var response1 = await client.GetAsync(UserUrl); - Assert.Equal(HttpStatusCode.OK, response1.StatusCode); + response1.Should().HaveStatusCode(HttpStatusCode.OK); var response2 = await client.GetAsync(AdminUrl); - Assert.Equal(HttpStatusCode.Forbidden, response2.StatusCode); + response2.Should().HaveStatusCode(HttpStatusCode.Forbidden); } } @@ -59,9 +60,9 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsAdmin()) { var response1 = await client.GetAsync(UserUrl); - Assert.Equal(HttpStatusCode.OK, response1.StatusCode); + response1.Should().HaveStatusCode(HttpStatusCode.OK); var response2 = await client.GetAsync(AdminUrl); - Assert.Equal(HttpStatusCode.OK, response2.StatusCode); + response2.Should().HaveStatusCode(HttpStatusCode.OK); } } } 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); + } + } +} diff --git a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs b/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs index 8a44c852..c8a79e58 100644 --- a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs +++ b/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs @@ -14,7 +14,7 @@ namespace Timeline.Tests.Helpers.Authentication public static async Task CreateUserTokenAsync(this HttpClient client, string username, string password, int? expireOffset = null) { var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, ExpireOffset = expireOffset }); - response.AssertOk(); + response.Should().HaveStatusCodeOk(); var result = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); return result; } diff --git a/Timeline.Tests/Helpers/InvalidModelTestHelpers.cs b/Timeline.Tests/Helpers/InvalidModelTestHelpers.cs index 1c079d0e..af432095 100644 --- a/Timeline.Tests/Helpers/InvalidModelTestHelpers.cs +++ b/Timeline.Tests/Helpers/InvalidModelTestHelpers.cs @@ -1,8 +1,6 @@ -using System.Net; using System.Net.Http; using System.Threading.Tasks; using Timeline.Models.Http; -using Xunit; namespace Timeline.Tests.Helpers { @@ -11,17 +9,15 @@ namespace Timeline.Tests.Helpers public static async Task TestPostInvalidModel(HttpClient client, string url, T body) { var response = await client.PostAsJsonAsync(url, body); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - var responseBody = await response.ReadBodyAsJson(); - Assert.Equal(CommonResponse.ErrorCodes.InvalidModel, responseBody.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(CommonResponse.ErrorCodes.InvalidModel); } public static async Task TestPutInvalidModel(HttpClient client, string url, T body) { var response = await client.PutAsJsonAsync(url, body); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - var responseBody = await response.ReadBodyAsJson(); - Assert.Equal(CommonResponse.ErrorCodes.InvalidModel, responseBody.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(CommonResponse.ErrorCodes.InvalidModel); } } } diff --git a/Timeline.Tests/Helpers/ResponseExtensions.cs b/Timeline.Tests/Helpers/ResponseExtensions.cs deleted file mode 100644 index 46c9e81d..00000000 --- a/Timeline.Tests/Helpers/ResponseExtensions.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Newtonsoft.Json; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Xunit; - -namespace Timeline.Tests.Helpers -{ - public static class ResponseExtensions - { - public static void AssertOk(this HttpResponseMessage response) - { - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - public static void AssertNotFound(this HttpResponseMessage response) - { - Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); - } - - public static void AssertBadRequest(this HttpResponseMessage response) - { - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - } - - public static async Task AssertIsPutCreated(this HttpResponseMessage response) - { - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - var body = await response.ReadBodyAsJson(); - Assert.Equal(CommonPutResponse.CreatedCode, body.Code); - } - - public static async Task AssertIsPutModified(this HttpResponseMessage response) - { - response.AssertOk(); - var body = await response.ReadBodyAsJson(); - Assert.Equal(CommonPutResponse.ModifiedCode, body.Code); - } - - - public static async Task AssertIsDeleteDeleted(this HttpResponseMessage response) - { - response.AssertOk(); - var body = await response.ReadBodyAsJson(); - Assert.Equal(CommonDeleteResponse.DeletedCode, body.Code); - } - - public static async Task AssertIsDeleteNotExist(this HttpResponseMessage response) - { - response.AssertOk(); - var body = await response.ReadBodyAsJson(); - Assert.Equal(CommonDeleteResponse.NotExistsCode, body.Code); - } - - public static async Task ReadBodyAsJson(this HttpResponseMessage response) - { - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - } - } -} diff --git a/Timeline.Tests/Helpers/UserInfoComparers.cs b/Timeline.Tests/Helpers/UserInfoComparers.cs deleted file mode 100644 index 1a1c652d..00000000 --- a/Timeline.Tests/Helpers/UserInfoComparers.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Collections.Generic; -using Timeline.Models; - -namespace Timeline.Tests.Helpers -{ - public static class UserInfoComparers - { - public static IEqualityComparer EqualityComparer { get; } = new EqualityComparerImpl(); - public static IComparer Comparer { get; } = Comparer.Create(Compare); - - - private class EqualityComparerImpl : IEqualityComparer - { - bool IEqualityComparer.Equals(UserInfo x, UserInfo y) - { - return Compare(x, y) == 0; - } - - int IEqualityComparer.GetHashCode(UserInfo obj) - { - return obj.Username.GetHashCode() ^ obj.Administrator.GetHashCode(); - } - } - - public static int Compare(UserInfo left, UserInfo right) - { - if (left == null) - { - if (right == null) - return 0; - return -1; - } - - if (right == null) - return 1; - - var uc = string.Compare(left.Username, right.Username); - if (uc != 0) - return uc; - - if (left.Administrator == right.Administrator) - return 0; - - return left.Administrator ? -1 : 1; - } - } -} diff --git a/Timeline.Tests/Mock/Data/TestUsers.cs b/Timeline.Tests/Mock/Data/TestUsers.cs index d784e48c..f34f62c5 100644 --- a/Timeline.Tests/Mock/Data/TestUsers.cs +++ b/Timeline.Tests/Mock/Data/TestUsers.cs @@ -3,7 +3,6 @@ using System.Linq; using Timeline.Entities; using Timeline.Models; using Timeline.Services; -using Timeline.Tests.Helpers; namespace Timeline.Tests.Mock.Data { @@ -34,13 +33,12 @@ namespace Timeline.Tests.Mock.Data var mockUserInfos = mockUsers.Select(u => UserUtility.CreateUserInfo(u)).ToList(); UserUserInfo = mockUserInfos[0]; AdminUserInfo = mockUserInfos[1]; - mockUserInfos.Sort(UserInfoComparers.Comparer); UserInfos = mockUserInfos; } public const string UserUsername = "user"; public const string AdminUsername = "admin"; - public const string UserPassword= "user"; + public const string UserPassword = "user"; public const string AdminPassword = "admin"; internal static IReadOnlyList Users { get; } diff --git a/Timeline.Tests/Timeline.Tests.csproj b/Timeline.Tests/Timeline.Tests.csproj index 854c63ac..72bbc418 100644 --- a/Timeline.Tests/Timeline.Tests.csproj +++ b/Timeline.Tests/Timeline.Tests.csproj @@ -9,6 +9,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Timeline.Tests/TokenUnitTest.cs b/Timeline.Tests/TokenUnitTest.cs index 5f3b8e6d..86f51c0b 100644 --- a/Timeline.Tests/TokenUnitTest.cs +++ b/Timeline.Tests/TokenUnitTest.cs @@ -13,6 +13,7 @@ using Timeline.Tests.Mock.Data; using Timeline.Tests.Mock.Services; using Xunit; using Xunit.Abstractions; +using FluentAssertions; namespace Timeline.Tests { @@ -70,9 +71,8 @@ namespace Timeline.Tests { var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = "usernotexist", Password = "???" }); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - var body = await response.ReadBodyAsJson(); - Assert.Equal(TokenController.ErrorCodes.Create_UserNotExist, body.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Create_UserNotExist); } } @@ -83,9 +83,8 @@ namespace Timeline.Tests { var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = MockUsers.UserUsername, Password = "???" }); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - var body = await response.ReadBodyAsJson(); - Assert.Equal(TokenController.ErrorCodes.Create_BadPassword, body.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Create_BadPassword); } } @@ -96,10 +95,10 @@ namespace Timeline.Tests { var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = MockUsers.UserUsername, Password = MockUsers.UserPassword }); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var body = await response.ReadBodyAsJson(); - Assert.NotEmpty(body.Token); - Assert.Equal(MockUsers.UserUserInfo, body.User, UserInfoComparers.EqualityComparer); + var body = response.Should().HaveStatusCodeOk() + .And.Should().HaveBodyAsJson().Which; + body.Token.Should().NotBeNullOrWhiteSpace(); + body.User.Should().BeEquivalentTo(MockUsers.UserUserInfo); } } @@ -119,9 +118,8 @@ namespace Timeline.Tests using (var client = _factory.CreateDefaultClient()) { var response = await client.PostAsJsonAsync(VerifyTokenUrl, new VerifyTokenRequest { Token = "bad token hahaha" }); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - var body = await response.ReadBodyAsJson(); - Assert.Equal(TokenController.ErrorCodes.Verify_BadToken, body.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Verify_BadToken); } } @@ -148,9 +146,9 @@ namespace Timeline.Tests // test against bad version var response = await client.PostAsJsonAsync(VerifyTokenUrl, new VerifyTokenRequest { Token = token }); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - var body = await response.ReadBodyAsJson(); - Assert.Equal(TokenController.ErrorCodes.Verify_BadVersion, body.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Verify_BadVersion); + // create another token var token2 = (await client.CreateUserTokenAsync(username, password)).Token; @@ -160,9 +158,8 @@ namespace Timeline.Tests // test against user not exist var response2 = await client.PostAsJsonAsync(VerifyTokenUrl, new VerifyTokenRequest { Token = token }); - Assert.Equal(HttpStatusCode.BadRequest, response2.StatusCode); - var body2 = await response2.ReadBodyAsJson(); - Assert.Equal(TokenController.ErrorCodes.Verify_UserNotExist, body2.Code); + response2.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Verify_UserNotExist); } } } @@ -179,8 +176,8 @@ namespace Timeline.Tests var token = (await client.CreateUserTokenAsync(MockUsers.UserUsername, MockUsers.UserPassword, 1)).Token; var response = await client.PostAsJsonAsync(VerifyTokenUrl, new VerifyTokenRequest { Token = token }); - var body = await response.ReadBodyAsJson(); - Assert.Equal(TokenController.ErrorCodes.Verify_Expired, body.Code); + response.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Verify_Expired); mockClock.MockCurrentTime = null; } } @@ -193,9 +190,9 @@ namespace Timeline.Tests var createTokenResult = await client.CreateUserTokenAsync(MockUsers.UserUsername, MockUsers.UserPassword); var response = await client.PostAsJsonAsync(VerifyTokenUrl, new VerifyTokenRequest { Token = createTokenResult.Token }); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var body = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - Assert.Equal(MockUsers.UserUserInfo, body.User, UserInfoComparers.EqualityComparer); + response.Should().HaveStatusCodeOk() + .And.Should().HaveBodyAsJson() + .Which.User.Should().BeEquivalentTo(MockUsers.UserUserInfo); } } } diff --git a/Timeline.Tests/UserUnitTest.cs b/Timeline.Tests/UserUnitTest.cs index c5c91d34..054d9caa 100644 --- a/Timeline.Tests/UserUnitTest.cs +++ b/Timeline.Tests/UserUnitTest.cs @@ -1,3 +1,4 @@ +using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; using System.Net; using System.Net.Http; @@ -28,15 +29,9 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsAdmin()) { var res = await client.GetAsync("users"); - Assert.Equal(HttpStatusCode.OK, res.StatusCode); - // Because tests are running asyncronized. So database may be modified and // we can't check the exact user lists at this point. So only check the format. - - // var users = (await res.ReadBodyAsJson()).ToList(); - // users.Sort(UserInfoComparers.Comparer); - // Assert.Equal(MockUsers.UserInfos, users, UserInfoComparers.EqualityComparer); - await res.ReadBodyAsJson(); + res.Should().HaveStatusCodeOk().And.Should().HaveBodyAsJson(); } } @@ -46,9 +41,9 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsAdmin()) { var res = await client.GetAsync("users/" + MockUsers.UserUsername); - res.AssertOk(); - var user = await res.ReadBodyAsJson(); - Assert.Equal(MockUsers.UserUserInfo, user, UserInfoComparers.EqualityComparer); + res.Should().HaveStatusCodeOk() + .And.Should().HaveBodyAsJson() + .Which.Should().BeEquivalentTo(MockUsers.UserUserInfo); } } @@ -58,9 +53,8 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsAdmin()) { var res = await client.GetAsync("users/usernotexist"); - res.AssertNotFound(); - var body = await res.ReadBodyAsJson(); - Assert.Equal(UserController.ErrorCodes.Get_NotExist, body.Code); + res.Should().HaveStatusCodeNotFound() + .And.Should().HaveBodyAsCommonResponseWithCode(UserController.ErrorCodes.Get_NotExist); } } @@ -80,9 +74,9 @@ namespace Timeline.Tests async Task CheckAdministrator(bool administrator) { var res = await client.GetAsync(url); - res.AssertOk(); - var body = await res.ReadBodyAsJson(); - Assert.Equal(administrator, body.Administrator); + res.Should().HaveStatusCodeOk() + .And.Should().HaveBodyAsJson() + .Which.Administrator.Should().Be(administrator); } { @@ -92,7 +86,7 @@ namespace Timeline.Tests Password = password, Administrator = false }); - await res.AssertIsPutCreated(); + res.Should().BePutCreated(); await CheckAdministrator(false); } @@ -103,38 +97,37 @@ namespace Timeline.Tests Password = password, Administrator = true }); - await res.AssertIsPutModified(); + res.Should().BePutModified(); await CheckAdministrator(true); } // Patch Not Exist { var res = await client.PatchAsJsonAsync("users/usernotexist", new UserPatchRequest { }); - res.AssertNotFound(); - var body = await res.ReadBodyAsJson(); - Assert.Equal(UserController.ErrorCodes.Patch_NotExist, body.Code); + res.Should().HaveStatusCodeNotFound() + .And.Should().HaveBodyAsCommonResponseWithCode(UserController.ErrorCodes.Patch_NotExist); } // Patch Success { var res = await client.PatchAsJsonAsync(url, new UserPatchRequest { Administrator = false }); - res.AssertOk(); + res.Should().HaveStatusCodeOk(); await CheckAdministrator(false); } // Delete Deleted { var res = await client.DeleteAsync(url); - await res.AssertIsDeleteDeleted(); + res.Should().BeDeleteDeleted(); var res2 = await client.GetAsync(url); - res2.AssertNotFound(); + res2.Should().HaveStatusCodeNotFound(); } // Delete Not Exist { var res = await client.DeleteAsync(url); - await res.AssertIsDeleteNotExist(); + res.Should().BeDeleteNotExist(); } } } @@ -176,9 +169,8 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsUser()) { var res = await client.PostAsJsonAsync(url, new ChangePasswordRequest { OldPassword = "???", NewPassword = "???" }); - res.AssertBadRequest(); - var body = await res.ReadBodyAsJson(); - Assert.Equal(UserController.ErrorCodes.ChangePassword_BadOldPassword, body.Code); + res.Should().HaveStatusCodeBadRequest() + .And.Should().HaveBodyAsCommonResponseWithCode(UserController.ErrorCodes.ChangePassword_BadOldPassword); } } @@ -192,14 +184,14 @@ namespace Timeline.Tests using (var client = await _factory.CreateClientAsAdmin()) { var res = await client.PutAsJsonAsync("users/" + username, new UserPutRequest { Password = password, Administrator = false }); - Assert.Equal(HttpStatusCode.Created, res.StatusCode); + res.Should().BePutCreated(); } using (var client = await _factory.CreateClientWithCredential(username, password)) { const string newPassword = "new"; var res = await client.PostAsJsonAsync(url, new ChangePasswordRequest { OldPassword = password, NewPassword = newPassword }); - res.AssertOk(); + res.Should().HaveStatusCodeOk(); await client.CreateUserTokenAsync(username, newPassword); } } -- cgit v1.2.3 From 39cadb8c493ad66bb472b119eb63146db8e58701 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 11 Aug 2019 15:36:06 +0800 Subject: Clean code. --- Timeline.Tests/AuthorizationUnitTest.cs | 2 +- Timeline.Tests/TokenUnitTest.cs | 4 +--- Timeline.Tests/UserUnitTest.cs | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/AuthorizationUnitTest.cs b/Timeline.Tests/AuthorizationUnitTest.cs index 3df4d0fd..6f52a12d 100644 --- a/Timeline.Tests/AuthorizationUnitTest.cs +++ b/Timeline.Tests/AuthorizationUnitTest.cs @@ -1,3 +1,4 @@ +using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; using System.Net; using System.Threading.Tasks; @@ -5,7 +6,6 @@ using Timeline.Tests.Helpers; using Timeline.Tests.Helpers.Authentication; using Xunit; using Xunit.Abstractions; -using FluentAssertions; namespace Timeline.Tests { diff --git a/Timeline.Tests/TokenUnitTest.cs b/Timeline.Tests/TokenUnitTest.cs index 86f51c0b..b5d8a2c8 100644 --- a/Timeline.Tests/TokenUnitTest.cs +++ b/Timeline.Tests/TokenUnitTest.cs @@ -1,8 +1,7 @@ +using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using System; -using System.Net; using System.Net.Http; using Timeline.Controllers; using Timeline.Models.Http; @@ -13,7 +12,6 @@ using Timeline.Tests.Mock.Data; using Timeline.Tests.Mock.Services; using Xunit; using Xunit.Abstractions; -using FluentAssertions; namespace Timeline.Tests { diff --git a/Timeline.Tests/UserUnitTest.cs b/Timeline.Tests/UserUnitTest.cs index 054d9caa..1f72000c 100644 --- a/Timeline.Tests/UserUnitTest.cs +++ b/Timeline.Tests/UserUnitTest.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; -using System.Net; using System.Net.Http; using System.Threading.Tasks; using Timeline.Controllers; -- cgit v1.2.3 From 6f4924af35e4620ccf11145e28be9490773155f6 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') 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