diff options
author | crupest <crupest@outlook.com> | 2019-11-20 00:28:53 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-11-20 00:28:53 +0800 |
commit | a72960e54a89bd31dcb8be8f52e097007dfd23e5 (patch) | |
tree | 55eaf43bda897148b0fa8a65406e7289aed3832e | |
parent | f3c7912caec2e9eee8a685d8751894f357528a71 (diff) | |
download | timeline-a72960e54a89bd31dcb8be8f52e097007dfd23e5.tar.gz timeline-a72960e54a89bd31dcb8be8f52e097007dfd23e5.tar.bz2 timeline-a72960e54a89bd31dcb8be8f52e097007dfd23e5.zip |
Clean and refactor tests.
22 files changed, 396 insertions, 462 deletions
diff --git a/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs b/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs index 819017c2..372ba8a7 100644 --- a/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs +++ b/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs @@ -15,7 +15,6 @@ using Timeline.Models.Http; using Timeline.Models.Validation;
using Timeline.Services;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Helpers.Authentication;
using Xunit;
namespace Timeline.Tests.Controllers
diff --git a/Timeline.Tests/Controllers/TokenControllerTest.cs b/Timeline.Tests/Controllers/TokenControllerTest.cs index 4a08ca0f..238fc237 100644 --- a/Timeline.Tests/Controllers/TokenControllerTest.cs +++ b/Timeline.Tests/Controllers/TokenControllerTest.cs @@ -8,8 +8,7 @@ using System.Threading.Tasks; using Timeline.Controllers;
using Timeline.Models.Http;
using Timeline.Services;
-using Timeline.Tests.Mock.Data;
-using Timeline.Tests.Mock.Services;
+using Timeline.Tests.Helpers;
using Xunit;
using static Timeline.ErrorCodes.Http.Token;
diff --git a/Timeline.Tests/Controllers/UserControllerTest.cs b/Timeline.Tests/Controllers/UserControllerTest.cs index 83b8cdcf..a5ca7a2b 100644 --- a/Timeline.Tests/Controllers/UserControllerTest.cs +++ b/Timeline.Tests/Controllers/UserControllerTest.cs @@ -12,7 +12,6 @@ using Timeline.Models; using Timeline.Models.Http;
using Timeline.Services;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Mock.Data;
using Xunit;
using static Timeline.ErrorCodes.Http.User;
diff --git a/Timeline.Tests/DatabaseTest.cs b/Timeline.Tests/DatabaseTest.cs index 20f57c40..a7b97c16 100644 --- a/Timeline.Tests/DatabaseTest.cs +++ b/Timeline.Tests/DatabaseTest.cs @@ -2,7 +2,7 @@ using System;
using System.Linq;
using Timeline.Entities;
-using Timeline.Tests.Mock.Data;
+using Timeline.Tests.Helpers;
using Xunit;
namespace Timeline.Tests
diff --git a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs b/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs deleted file mode 100644 index 4048bb73..00000000 --- a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Testing;
-using System;
-using System.Net.Http;
-using System.Threading.Tasks;
-using Timeline.Models.Http;
-using Timeline.Tests.Mock.Data;
-
-namespace Timeline.Tests.Helpers.Authentication
-{
- public enum AuthType
- {
- None,
- User,
- Admin
- }
-
- public static class AuthenticationExtensions
- {
- private const string CreateTokenUrl = "/token/create";
-
- public static async Task<CreateTokenResponse> CreateUserTokenAsync(this HttpClient client, string username, string password, int? expireOffset = null)
- {
- var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, Expire = expireOffset });
- return response.Should().HaveStatusCode(200)
- .And.HaveJsonBody<CreateTokenResponse>().Which;
- }
-
- public static async Task<HttpClient> CreateClientWithCredential<T>(this WebApplicationFactory<T> factory, string username, string password) where T : class
- {
- var client = factory.CreateDefaultClient();
- var token = (await client.CreateUserTokenAsync(username, password)).Token;
- client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
- return client;
- }
-
- public static Task<HttpClient> CreateClientAs<T>(this WebApplicationFactory<T> factory, MockUser user) where T : class
- {
- return CreateClientWithCredential(factory, user.Username, user.Password);
- }
-
- public static Task<HttpClient> CreateClientAsUser<T>(this WebApplicationFactory<T> factory) where T : class
- {
- return factory.CreateClientAs(MockUser.User);
- }
-
- public static Task<HttpClient> CreateClientAsAdmin<T>(this WebApplicationFactory<T> factory) where T : class
- {
- return factory.CreateClientAs(MockUser.Admin);
- }
-
- public static Task<HttpClient> CreateClientAs<T>(this WebApplicationFactory<T> factory, AuthType authType) where T : class
- {
- return authType switch
- {
- AuthType.None => Task.FromResult(factory.CreateDefaultClient()),
- AuthType.User => factory.CreateClientAsUser(),
- AuthType.Admin => factory.CreateClientAsAdmin(),
- _ => throw new InvalidOperationException("Unknown auth type.")
- };
- }
-
- public static MockUser GetMockUser(this AuthType authType)
- {
- return authType switch
- {
- AuthType.None => null,
- AuthType.User => MockUser.User,
- AuthType.Admin => MockUser.Admin,
- _ => throw new InvalidOperationException("Unknown auth type.")
- };
- }
-
- public static string GetUsername(this AuthType authType) => authType.GetMockUser().Username;
- }
-}
diff --git a/Timeline.Tests/Mock/Data/TestUsers.cs b/Timeline.Tests/Helpers/MockUser.cs index 443d3cf9..8d738525 100644 --- a/Timeline.Tests/Mock/Data/TestUsers.cs +++ b/Timeline.Tests/Helpers/MockUser.cs @@ -1,25 +1,24 @@ -using System.Collections.Generic;
-using Timeline.Models;
-
-namespace Timeline.Tests.Mock.Data
-{
- public class MockUser
- {
- public MockUser(string username, string password, bool administrator)
- {
- Info = new UserInfo(username, administrator);
- Password = password;
- }
-
- public UserInfo Info { get; set; }
- public string Username => Info.Username;
- public string Password { get; set; }
- public bool Administrator => Info.Administrator;
-
-
- public static MockUser User { get; } = new MockUser("user", "userpassword", false);
- public static MockUser Admin { get; } = new MockUser("admin", "adminpassword", true);
-
- public static IReadOnlyList<UserInfo> UserInfoList { get; } = new List<UserInfo> { User.Info, Admin.Info };
- }
-}
+using System.Collections.Generic; +using Timeline.Models; + +namespace Timeline.Tests.Helpers +{ + public class MockUser + { + public MockUser(string username, string password, bool administrator) + { + Info = new UserInfo(username, administrator); + Password = password; + } + + public UserInfo Info { get; set; } + public string Username => Info.Username; + public string Password { get; set; } + public bool Administrator => Info.Administrator; + + public static MockUser User { get; } = new MockUser("user", "userpassword", false); + public static MockUser Admin { get; } = new MockUser("admin", "adminpassword", true); + + public static IReadOnlyList<UserInfo> UserInfoList { get; } = new List<UserInfo> { User.Info, Admin.Info }; + } +} diff --git a/Timeline.Tests/Helpers/Authentication/PrincipalHelper.cs b/Timeline.Tests/Helpers/PrincipalHelper.cs index 214472a2..89f3f7b1 100644 --- a/Timeline.Tests/Helpers/Authentication/PrincipalHelper.cs +++ b/Timeline.Tests/Helpers/PrincipalHelper.cs @@ -1,23 +1,23 @@ -using System.Linq;
-using System.Security.Claims;
-using Timeline.Models;
-
-namespace Timeline.Tests.Helpers.Authentication
-{
- public static class PrincipalHelper
- {
- internal const string AuthScheme = "TESTAUTH";
-
- internal static ClaimsPrincipal Create(string username, bool administrator)
- {
- var identity = new ClaimsIdentity(AuthScheme);
- identity.AddClaim(new Claim(identity.NameClaimType, username, ClaimValueTypes.String));
- identity.AddClaims(UserRoleConvert.ToArray(administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String)));
-
- var principal = new ClaimsPrincipal();
- principal.AddIdentity(identity);
-
- return principal;
- }
- }
-}
+using System.Linq; +using System.Security.Claims; +using Timeline.Models; + +namespace Timeline.Tests.Helpers +{ + public static class PrincipalHelper + { + internal const string AuthScheme = "TESTAUTH"; + + internal static ClaimsPrincipal Create(string username, bool administrator) + { + var identity = new ClaimsIdentity(AuthScheme); + identity.AddClaim(new Claim(identity.NameClaimType, username, ClaimValueTypes.String)); + identity.AddClaims(UserRoleConvert.ToArray(administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String))); + + var principal = new ClaimsPrincipal(); + principal.AddIdentity(identity); + + return principal; + } + } +} diff --git a/Timeline.Tests/Helpers/TestApplication.cs b/Timeline.Tests/Helpers/TestApplication.cs index 5862f452..a624da6b 100644 --- a/Timeline.Tests/Helpers/TestApplication.cs +++ b/Timeline.Tests/Helpers/TestApplication.cs @@ -1,10 +1,8 @@ using Microsoft.AspNetCore.Mvc.Testing;
-using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using Timeline.Entities;
-using Timeline.Tests.Mock.Data;
namespace Timeline.Tests.Helpers
{
diff --git a/Timeline.Tests/Mock/Services/TestClock.cs b/Timeline.Tests/Helpers/TestClock.cs index 6671395a..12b320d3 100644 --- a/Timeline.Tests/Mock/Services/TestClock.cs +++ b/Timeline.Tests/Helpers/TestClock.cs @@ -1,15 +1,15 @@ -using System;
-using Timeline.Services;
-
-namespace Timeline.Tests.Mock.Services
-{
- public class TestClock : IClock
- {
- public DateTime? MockCurrentTime { get; set; } = null;
-
- public DateTime GetCurrentTime()
- {
- return MockCurrentTime.GetValueOrDefault(DateTime.Now);
- }
- }
-}
+using System; +using Timeline.Services; + +namespace Timeline.Tests.Helpers +{ + public class TestClock : IClock + { + public DateTime? MockCurrentTime { get; set; } = null; + + public DateTime GetCurrentTime() + { + return MockCurrentTime.GetValueOrDefault(DateTime.Now); + } + } +} diff --git a/Timeline.Tests/Mock/Data/TestDatabase.cs b/Timeline.Tests/Helpers/TestDatabase.cs index 1f396177..10224c27 100644 --- a/Timeline.Tests/Mock/Data/TestDatabase.cs +++ b/Timeline.Tests/Helpers/TestDatabase.cs @@ -1,88 +1,89 @@ -using Microsoft.Data.Sqlite;
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Timeline.Entities;
-using Timeline.Models;
-using Timeline.Services;
-
-namespace Timeline.Tests.Mock.Data
-{
- public class TestDatabase : IDisposable
- {
- // currently password service is thread safe, so we share a static one.
- private static PasswordService PasswordService { get; } = new PasswordService();
-
- private static User CreateEntityFromMock(MockUser user)
- {
- return new User
- {
- Name = user.Username,
- EncryptedPassword = PasswordService.HashPassword(user.Password),
- RoleString = UserRoleConvert.ToString(user.Administrator),
- Avatar = null
- };
- }
-
- private static IEnumerable<User> CreateDefaultMockEntities()
- {
- // emmmmmmm. Never reuse the user instances because EF Core uses them, which will cause strange things.
- yield return CreateEntityFromMock(MockUser.User);
- yield return CreateEntityFromMock(MockUser.Admin);
- }
-
- private static void InitDatabase(DatabaseContext context)
- {
- context.Database.EnsureCreated();
- context.Users.AddRange(CreateDefaultMockEntities());
- context.SaveChanges();
- }
-
- public TestDatabase()
- {
- Connection = new SqliteConnection("Data Source=:memory:;");
- Connection.Open();
-
- var options = new DbContextOptionsBuilder<DatabaseContext>()
- .UseSqlite(Connection)
- .Options;
-
- Context = new DatabaseContext(options);
-
- InitDatabase(Context);
- }
-
- private List<MockUser> _extraMockUsers;
-
- public IReadOnlyList<MockUser> ExtraMockUsers => _extraMockUsers;
-
- public void CreateExtraMockUsers(int count)
- {
- if (count <= 0)
- throw new ArgumentOutOfRangeException(nameof(count), count, "Additional user count must be bigger than 0.");
- if (_extraMockUsers != null)
- throw new InvalidOperationException("Already create mock users.");
-
- _extraMockUsers = new List<MockUser>();
- for (int i = 0; i < count; i++)
- {
- _extraMockUsers.Add(new MockUser($"user{i}", $"password", false));
- }
-
- Context.AddRange(_extraMockUsers.Select(u => CreateEntityFromMock(u)));
- Context.SaveChanges();
- }
-
- public void Dispose()
- {
- Context.Dispose();
-
- Connection.Close();
- Connection.Dispose();
- }
-
- public SqliteConnection Connection { get; }
- public DatabaseContext Context { get; }
- }
-}
+using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using Timeline.Entities; +using Timeline.Models; +using Timeline.Services; + +namespace Timeline.Tests.Helpers +{ + public class TestDatabase : IDisposable + { + // currently password service is thread safe, so we share a static one. + private static PasswordService PasswordService { get; } = new PasswordService(); + + private static User CreateEntityFromMock(MockUser user) + { + return new User + { + Name = user.Username, + EncryptedPassword = PasswordService.HashPassword(user.Password), + RoleString = UserRoleConvert.ToString(user.Administrator), + Avatar = null + }; + } + + private static IEnumerable<User> CreateDefaultMockEntities() + { + // emmmmmmm. Never reuse the user instances because EF Core uses them, which will cause strange things. + yield return CreateEntityFromMock(MockUser.User); + yield return CreateEntityFromMock(MockUser.Admin); + } + + private static void InitDatabase(DatabaseContext context) + { + context.Database.EnsureCreated(); + context.Users.AddRange(CreateDefaultMockEntities()); + context.SaveChanges(); + } + + public SqliteConnection Connection { get; } + public DatabaseContext Context { get; } + + public TestDatabase() + { + Connection = new SqliteConnection("Data Source=:memory:;"); + Connection.Open(); + + var options = new DbContextOptionsBuilder<DatabaseContext>() + .UseSqlite(Connection) + .Options; + + Context = new DatabaseContext(options); + + InitDatabase(Context); + } + + private List<MockUser> _extraMockUsers; + + public IReadOnlyList<MockUser> ExtraMockUsers => _extraMockUsers; + + public void CreateExtraMockUsers(int count) + { + if (count <= 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "Additional user count must be bigger than 0."); + if (_extraMockUsers != null) + throw new InvalidOperationException("Already create mock users."); + + _extraMockUsers = new List<MockUser>(); + for (int i = 0; i < count; i++) + { + _extraMockUsers.Add(new MockUser($"user{i}", $"password", false)); + } + + Context.AddRange(_extraMockUsers.Select(u => CreateEntityFromMock(u))); + Context.SaveChanges(); + } + + public void Dispose() + { + Context.Dispose(); + + Connection.Close(); + Connection.Dispose(); + } + + } +} diff --git a/Timeline.Tests/Helpers/UseCultureAttribute.cs b/Timeline.Tests/Helpers/UseCultureAttribute.cs index f0064c01..017d77a8 100644 --- a/Timeline.Tests/Helpers/UseCultureAttribute.cs +++ b/Timeline.Tests/Helpers/UseCultureAttribute.cs @@ -1,91 +1,94 @@ using System; using System.Globalization; -using System.Linq; using System.Reflection; using System.Threading; using Xunit.Sdk; -// Copied from https://github.com/xunit/samples.xunit/blob/master/UseCulture/UseCultureAttribute.cs -/// <summary> -/// Apply this attribute to your test method to replace the -/// <see cref="Thread.CurrentThread" /> <see cref="CultureInfo.CurrentCulture" /> and -/// <see cref="CultureInfo.CurrentUICulture" /> with another culture. -/// </summary> -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] -public class UseCultureAttribute : BeforeAfterTestAttribute +namespace Timeline.Tests.Helpers { - readonly Lazy<CultureInfo> culture; - readonly Lazy<CultureInfo> uiCulture; - - CultureInfo originalCulture; - CultureInfo originalUICulture; + // Copied from https://github.com/xunit/samples.xunit/blob/master/UseCulture/UseCultureAttribute.cs /// <summary> - /// Replaces the culture and UI culture of the current thread with - /// <paramref name="culture" /> + /// Apply this attribute to your test method to replace the + /// <see cref="Thread.CurrentThread" /> <see cref="CultureInfo.CurrentCulture" /> and + /// <see cref="CultureInfo.CurrentUICulture" /> with another culture. /// </summary> - /// <param name="culture">The name of the culture.</param> - /// <remarks> - /// <para> - /// This constructor overload uses <paramref name="culture" /> for both - /// <see cref="Culture" /> and <see cref="UICulture" />. - /// </para> - /// </remarks> - public UseCultureAttribute(string culture) - : this(culture, culture) { } - - /// <summary> - /// Replaces the culture and UI culture of the current thread with - /// <paramref name="culture" /> and <paramref name="uiCulture" /> - /// </summary> - /// <param name="culture">The name of the culture.</param> - /// <param name="uiCulture">The name of the UI culture.</param> - public UseCultureAttribute(string culture, string uiCulture) + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class UseCultureAttribute : BeforeAfterTestAttribute { - this.culture = new Lazy<CultureInfo>(() => new CultureInfo(culture, false)); - this.uiCulture = new Lazy<CultureInfo>(() => new CultureInfo(uiCulture, false)); - } + readonly Lazy<CultureInfo> culture; + readonly Lazy<CultureInfo> uiCulture; - /// <summary> - /// Gets the culture. - /// </summary> - public CultureInfo Culture { get { return culture.Value; } } + CultureInfo originalCulture; + CultureInfo originalUICulture; - /// <summary> - /// Gets the UI culture. - /// </summary> - public CultureInfo UICulture { get { return uiCulture.Value; } } + /// <summary> + /// Replaces the culture and UI culture of the current thread with + /// <paramref name="culture" /> + /// </summary> + /// <param name="culture">The name of the culture.</param> + /// <remarks> + /// <para> + /// This constructor overload uses <paramref name="culture" /> for both + /// <see cref="Culture" /> and <see cref="UICulture" />. + /// </para> + /// </remarks> + public UseCultureAttribute(string culture) + : this(culture, culture) { } - /// <summary> - /// Stores the current <see cref="Thread.CurrentPrincipal" /> - /// <see cref="CultureInfo.CurrentCulture" /> and <see cref="CultureInfo.CurrentUICulture" /> - /// and replaces them with the new cultures defined in the constructor. - /// </summary> - /// <param name="methodUnderTest">The method under test</param> - public override void Before(MethodInfo methodUnderTest) - { - originalCulture = Thread.CurrentThread.CurrentCulture; - originalUICulture = Thread.CurrentThread.CurrentUICulture; + /// <summary> + /// Replaces the culture and UI culture of the current thread with + /// <paramref name="culture" /> and <paramref name="uiCulture" /> + /// </summary> + /// <param name="culture">The name of the culture.</param> + /// <param name="uiCulture">The name of the UI culture.</param> + public UseCultureAttribute(string culture, string uiCulture) + { + this.culture = new Lazy<CultureInfo>(() => new CultureInfo(culture, false)); + this.uiCulture = new Lazy<CultureInfo>(() => new CultureInfo(uiCulture, false)); + } - Thread.CurrentThread.CurrentCulture = Culture; - Thread.CurrentThread.CurrentUICulture = UICulture; + /// <summary> + /// Gets the culture. + /// </summary> + public CultureInfo Culture { get { return culture.Value; } } - CultureInfo.CurrentCulture.ClearCachedData(); - CultureInfo.CurrentUICulture.ClearCachedData(); - } + /// <summary> + /// Gets the UI culture. + /// </summary> + public CultureInfo UICulture { get { return uiCulture.Value; } } - /// <summary> - /// Restores the original <see cref="CultureInfo.CurrentCulture" /> and - /// <see cref="CultureInfo.CurrentUICulture" /> to <see cref="Thread.CurrentPrincipal" /> - /// </summary> - /// <param name="methodUnderTest">The method under test</param> - public override void After(MethodInfo methodUnderTest) - { - Thread.CurrentThread.CurrentCulture = originalCulture; - Thread.CurrentThread.CurrentUICulture = originalUICulture; + /// <summary> + /// Stores the current <see cref="Thread.CurrentPrincipal" /> + /// <see cref="CultureInfo.CurrentCulture" /> and <see cref="CultureInfo.CurrentUICulture" /> + /// and replaces them with the new cultures defined in the constructor. + /// </summary> + /// <param name="methodUnderTest">The method under test</param> + public override void Before(MethodInfo methodUnderTest) + { + originalCulture = Thread.CurrentThread.CurrentCulture; + originalUICulture = Thread.CurrentThread.CurrentUICulture; + + Thread.CurrentThread.CurrentCulture = Culture; + Thread.CurrentThread.CurrentUICulture = UICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + + /// <summary> + /// Restores the original <see cref="CultureInfo.CurrentCulture" /> and + /// <see cref="CultureInfo.CurrentUICulture" /> to <see cref="Thread.CurrentPrincipal" /> + /// </summary> + /// <param name="methodUnderTest">The method under test</param> + public override void After(MethodInfo methodUnderTest) + { + Thread.CurrentThread.CurrentCulture = originalCulture; + Thread.CurrentThread.CurrentUICulture = originalUICulture; - CultureInfo.CurrentCulture.ClearCachedData(); - CultureInfo.CurrentUICulture.ClearCachedData(); + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } } } diff --git a/Timeline.Tests/IntegratedTests/AuthorizationTest.cs b/Timeline.Tests/IntegratedTests/AuthorizationTest.cs index a31d98f5..0bc094af 100644 --- a/Timeline.Tests/IntegratedTests/AuthorizationTest.cs +++ b/Timeline.Tests/IntegratedTests/AuthorizationTest.cs @@ -1,28 +1,17 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
-using System;
using System.Net;
using System.Threading.Tasks;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Helpers.Authentication;
using Xunit;
namespace Timeline.Tests.IntegratedTests
{
- public class AuthorizationTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ public class AuthorizationTest : IntegratedTestBase
{
- private readonly TestApplication _testApp;
- private readonly WebApplicationFactory<Startup> _factory;
-
public AuthorizationTest(WebApplicationFactory<Startup> factory)
+ : base(factory)
{
- _testApp = new TestApplication(factory);
- _factory = _testApp.Factory;
- }
-
- public void Dispose()
- {
- _testApp.Dispose();
}
private const string BaseUrl = "testing/auth/";
@@ -33,7 +22,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task UnauthenticationTest()
{
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
var response = await client.GetAsync(AuthorizeUrl);
response.Should().HaveStatusCode(HttpStatusCode.Unauthorized);
}
@@ -41,7 +30,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task AuthenticationTest()
{
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
var response = await client.GetAsync(AuthorizeUrl);
response.Should().HaveStatusCode(HttpStatusCode.OK);
}
@@ -49,7 +38,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task UserAuthorizationTest()
{
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
var response1 = await client.GetAsync(UserUrl);
response1.Should().HaveStatusCode(HttpStatusCode.OK);
var response2 = await client.GetAsync(AdminUrl);
@@ -59,7 +48,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task AdminAuthorizationTest()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var response1 = await client.GetAsync(UserUrl);
response1.Should().HaveStatusCode(HttpStatusCode.OK);
var response2 = await client.GetAsync(AdminUrl);
diff --git a/Timeline.Tests/IntegratedTests/I18nTest.cs b/Timeline.Tests/IntegratedTests/I18nTest.cs index 67bbea5c..855179af 100644 --- a/Timeline.Tests/IntegratedTests/I18nTest.cs +++ b/Timeline.Tests/IntegratedTests/I18nTest.cs @@ -1,32 +1,28 @@ -using Microsoft.AspNetCore.Mvc.Testing;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc.Testing;
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Timeline.Tests.Helpers;
using Xunit;
-using FluentAssertions;
namespace Timeline.Tests.IntegratedTests
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1054:Uri parameters should not be strings")]
- public class I18nTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ public class I18nTest : IntegratedTestBase
{
- private readonly TestApplication _testApp;
private readonly HttpClient _client;
public I18nTest(WebApplicationFactory<Startup> factory)
+ : base(factory)
{
- _testApp = new TestApplication(factory);
- _client = _testApp.Factory.CreateDefaultClient();
+ _client = Factory.CreateDefaultClient();
}
- public void Dispose()
+ protected override void OnDispose()
{
_client.Dispose();
- _testApp.Dispose();
}
private const string DirectUrl = "testing/i18n/direct";
diff --git a/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs b/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs index 2dfaf82e..242a452d 100644 --- a/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs +++ b/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs @@ -1,14 +1,37 @@ using Microsoft.AspNetCore.Mvc.Testing; using System; using System.Collections.Generic; -using System.Linq; +using System.Net.Http; using System.Threading.Tasks; +using Timeline.Models.Http; using Timeline.Tests.Helpers; -using Timeline.Tests.Mock.Data; using Xunit; namespace Timeline.Tests.IntegratedTests { + public enum AuthType + { + None, + User, + Admin + } + + public static class AuthTypeExtensions + { + public static MockUser GetMockUser(this AuthType authType) + { + return authType switch + { + AuthType.None => null, + AuthType.User => MockUser.User, + AuthType.Admin => MockUser.Admin, + _ => throw new InvalidOperationException("Unknown auth type.") + }; + } + + public static string GetUsername(this AuthType authType) => authType.GetMockUser().Username; + } + public abstract class IntegratedTestBase : IClassFixture<WebApplicationFactory<Startup>>, IDisposable { protected TestApplication TestApp { get; } @@ -20,8 +43,14 @@ namespace Timeline.Tests.IntegratedTests TestApp = new TestApplication(factory); } - public virtual void Dispose() + protected virtual void OnDispose() + { + + } + + public void Dispose() { + OnDispose(); TestApp.Dispose(); } @@ -31,5 +60,35 @@ namespace Timeline.Tests.IntegratedTests } protected IReadOnlyList<MockUser> ExtraMockUsers => TestApp.Database.ExtraMockUsers; + + public Task<HttpClient> CreateClientWithNoAuth() + { + return Task.FromResult(Factory.CreateDefaultClient()); + } + + public async Task<HttpClient> CreateClientWithCredential(string username, string password) + { + var client = Factory.CreateDefaultClient(); + var response = await client.PostAsJsonAsync("/token/create", + new CreateTokenRequest { Username = username, Password = password }); + var token = response.Should().HaveStatusCode(200) + .And.HaveJsonBody<CreateTokenResponse>().Which.Token; + client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); + return client; + } + + public Task<HttpClient> CreateClientAs(MockUser user) + { + if (user == null) + return CreateClientWithNoAuth(); + return CreateClientWithCredential(user.Username, user.Password); + } + + public Task<HttpClient> CreateClientAs(AuthType authType) => CreateClientAs(authType.GetMockUser()); + + + public Task<HttpClient> CreateClientAsUser() => CreateClientAs(MockUser.User); + public Task<HttpClient> CreateClientAsAdmin() => CreateClientAs(MockUser.Admin); + } } diff --git a/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs b/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs index 705675f9..9dae4c3e 100644 --- a/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs +++ b/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs @@ -1,17 +1,12 @@ using FluentAssertions; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Testing; using System; using System.Collections.Generic; -using System.Linq; using System.Net.Http; -using System.Text.Json; using System.Threading.Tasks; using Timeline.Models; using Timeline.Models.Http; using Timeline.Tests.Helpers; -using Timeline.Tests.Helpers.Authentication; -using Timeline.Tests.Mock.Data; using Xunit; namespace Timeline.Tests.IntegratedTests @@ -27,7 +22,7 @@ namespace Timeline.Tests.IntegratedTests [Fact] public async Task TimelineGet_Should_Work() { - using var client = Factory.CreateDefaultClient(); + using var client = await CreateClientWithNoAuth(); var res = await client.GetAsync("users/user/timeline"); var body = res.Should().HaveStatusCode(200) .And.HaveJsonBody<BaseTimelineInfo>().Which; @@ -40,7 +35,7 @@ namespace Timeline.Tests.IntegratedTests [Fact] public async Task Description_Should_Work() { - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); async Task AssertDescription(string description) { @@ -78,7 +73,7 @@ namespace Timeline.Tests.IntegratedTests { const string getUrl = "users/user/timeline"; const string changeUrl = "users/user/timeline/op/member"; - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); async Task AssertMembers(IList<string> members) { @@ -137,7 +132,7 @@ namespace Timeline.Tests.IntegratedTests [InlineData(AuthType.Admin, 200, 200, 200, 200, 200)] public async Task Permission_Timeline(AuthType authType, int get, int opPropertyUser, int opPropertyAdmin, int opMemberUser, int opMemberAdmin) { - using var client = await Factory.CreateClientAs(authType); + using var client = await CreateClientAs(authType); { var res = await client.GetAsync("users/user/timeline"); res.Should().HaveStatusCode(get); @@ -175,13 +170,13 @@ namespace Timeline.Tests.IntegratedTests const string adminUrl = "users/admin/timeline/posts"; { // default visibility is registered { - using var client = Factory.CreateDefaultClient(); + using var client = await CreateClientWithNoAuth(); var res = await client.GetAsync(userUrl); res.Should().HaveStatusCode(403); } { - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); var res = await client.GetAsync(adminUrl); res.Should().HaveStatusCode(200); } @@ -189,13 +184,13 @@ namespace Timeline.Tests.IntegratedTests { // change visibility to public { - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); var res = await client.PostAsJsonAsync("users/user/timeline/op/property", new TimelinePropertyChangeRequest { Visibility = TimelineVisibility.Public }); res.Should().HaveStatusCode(200); } { - using var client = Factory.CreateDefaultClient(); + using var client = await CreateClientWithNoAuth(); var res = await client.GetAsync(userUrl); res.Should().HaveStatusCode(200); } @@ -203,7 +198,7 @@ namespace Timeline.Tests.IntegratedTests { // change visibility to private { - using var client = await Factory.CreateClientAsAdmin(); + using var client = await CreateClientAsAdmin(); { var res = await client.PostAsJsonAsync("users/user/timeline/op/property", new TimelinePropertyChangeRequest { Visibility = TimelineVisibility.Private }); @@ -216,28 +211,28 @@ namespace Timeline.Tests.IntegratedTests } } { - using var client = Factory.CreateDefaultClient(); + using var client = await CreateClientWithNoAuth(); var res = await client.GetAsync(userUrl); res.Should().HaveStatusCode(403); } { // user can't read admin's - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); var res = await client.GetAsync(adminUrl); res.Should().HaveStatusCode(403); } { // admin can read user's - using var client = await Factory.CreateClientAsAdmin(); + using var client = await CreateClientAsAdmin(); var res = await client.GetAsync(userUrl); res.Should().HaveStatusCode(200); } { // add member - using var client = await Factory.CreateClientAsAdmin(); + using var client = await CreateClientAsAdmin(); var res = await client.PostAsJsonAsync("users/admin/timeline/op/member", new TimelineMemberChangeRequest { Add = new List<string> { "user" } }); res.Should().HaveStatusCode(200); } { // now user can read admin's - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); var res = await client.GetAsync(adminUrl); res.Should().HaveStatusCode(200); } @@ -250,14 +245,14 @@ namespace Timeline.Tests.IntegratedTests { CreateExtraMockUsers(1); - using (var client = await Factory.CreateClientAsUser()) + using (var client = await CreateClientAsUser()) { var res = await client.PostAsJsonAsync("users/user/timeline/op/member", new TimelineMemberChangeRequest { Add = new List<string> { "user0" } }); res.Should().HaveStatusCode(200); } - using (var client = Factory.CreateDefaultClient()) + using (var client = await CreateClientWithNoAuth()) { { // no auth should get 401 var res = await client.PostAsJsonAsync("users/user/timeline/postop/create", @@ -266,7 +261,7 @@ namespace Timeline.Tests.IntegratedTests } } - using (var client = await Factory.CreateClientAsUser()) + using (var client = await CreateClientAsUser()) { { // post self's var res = await client.PostAsJsonAsync("users/user/timeline/postop/create", @@ -280,7 +275,7 @@ namespace Timeline.Tests.IntegratedTests } } - using (var client = await Factory.CreateClientAsAdmin()) + using (var client = await CreateClientAsAdmin()) { { // post as admin var res = await client.PostAsJsonAsync("users/user/timeline/postop/create", @@ -289,7 +284,7 @@ namespace Timeline.Tests.IntegratedTests } } - using (var client = await Factory.CreateClientAs(ExtraMockUsers[0])) + using (var client = await CreateClientAs(ExtraMockUsers[0])) { { // post as member var res = await client.PostAsJsonAsync("users/user/timeline/postop/create", @@ -306,7 +301,7 @@ namespace Timeline.Tests.IntegratedTests async Task<long> CreatePost(MockUser auth, string timeline) { - using var client = await Factory.CreateClientAs(auth); + using var client = await CreateClientAs(auth); var res = await client.PostAsJsonAsync($"users/{timeline}/timeline/postop/create", new TimelinePostCreateRequest { Content = "aaa" }); return res.Should().HaveStatusCode(200) @@ -314,7 +309,7 @@ namespace Timeline.Tests.IntegratedTests .Which.Id; } - using (var client = await Factory.CreateClientAsUser()) + using (var client = await CreateClientAsUser()) { var res = await client.PostAsJsonAsync("users/user/timeline/op/member", new TimelineMemberChangeRequest { Add = new List<string> { "user0", "user1" } }); @@ -322,7 +317,7 @@ namespace Timeline.Tests.IntegratedTests } { // no auth should get 401 - using var client = Factory.CreateDefaultClient(); + using var client = await CreateClientWithNoAuth(); var res = await client.PostAsJsonAsync("users/user/timeline/postop/delete", new TimelinePostDeleteRequest { Id = 12 }); res.Should().HaveStatusCode(401); @@ -330,7 +325,7 @@ namespace Timeline.Tests.IntegratedTests { // self can delete self var postId = await CreatePost(MockUser.User, "user"); - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); var res = await client.PostAsJsonAsync("users/user/timeline/postop/delete", new TimelinePostDeleteRequest { Id = postId }); res.Should().HaveStatusCode(200); @@ -338,7 +333,7 @@ namespace Timeline.Tests.IntegratedTests { // admin can delete any var postId = await CreatePost(MockUser.User, "user"); - using var client = await Factory.CreateClientAsAdmin(); + using var client = await CreateClientAsAdmin(); var res = await client.PostAsJsonAsync("users/user/timeline/postop/delete", new TimelinePostDeleteRequest { Id = postId }); res.Should().HaveStatusCode(200); @@ -346,7 +341,7 @@ namespace Timeline.Tests.IntegratedTests { // owner can delete other var postId = await CreatePost(ExtraMockUsers[0], "user"); - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); var res = await client.PostAsJsonAsync("users/user/timeline/postop/delete", new TimelinePostDeleteRequest { Id = postId }); res.Should().HaveStatusCode(200); @@ -354,7 +349,7 @@ namespace Timeline.Tests.IntegratedTests { // author can delete self var postId = await CreatePost(ExtraMockUsers[0], "user"); - using var client = await Factory.CreateClientAs(ExtraMockUsers[0]); + using var client = await CreateClientAs(ExtraMockUsers[0]); var res = await client.PostAsJsonAsync("users/user/timeline/postop/delete", new TimelinePostDeleteRequest { Id = postId }); res.Should().HaveStatusCode(200); @@ -362,7 +357,7 @@ namespace Timeline.Tests.IntegratedTests { // otherwise is forbidden var postId = await CreatePost(ExtraMockUsers[0], "user"); - using var client = await Factory.CreateClientAs(ExtraMockUsers[1]); + using var client = await CreateClientAs(ExtraMockUsers[1]); var res = await client.PostAsJsonAsync("users/user/timeline/postop/delete", new TimelinePostDeleteRequest { Id = postId }); res.Should().HaveStatusCode(403); @@ -373,7 +368,7 @@ namespace Timeline.Tests.IntegratedTests public async Task Post_Op_Should_Work() { { - using var client = await Factory.CreateClientAsUser(); + using var client = await CreateClientAsUser(); { var res = await client.GetAsync("users/user/timeline/posts"); res.Should().HaveStatusCode(200) @@ -459,6 +454,7 @@ namespace Timeline.Tests.IntegratedTests Time = createRes2.Time }); } + // TODO! Add post not exist tests. } } } diff --git a/Timeline.Tests/IntegratedTests/TokenTest.cs b/Timeline.Tests/IntegratedTests/TokenTest.cs index 111e8d8e..e62228fc 100644 --- a/Timeline.Tests/IntegratedTests/TokenTest.cs +++ b/Timeline.Tests/IntegratedTests/TokenTest.cs @@ -1,37 +1,33 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
-using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Timeline.Models.Http;
using Timeline.Services;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Helpers.Authentication;
-using Timeline.Tests.Mock.Data;
using Xunit;
using static Timeline.ErrorCodes.Http.Token;
namespace Timeline.Tests.IntegratedTests
{
- public class TokenTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ public class TokenTest : IntegratedTestBase
{
private const string CreateTokenUrl = "token/create";
private const string VerifyTokenUrl = "token/verify";
- private readonly TestApplication _testApp;
- private readonly WebApplicationFactory<Startup> _factory;
-
public TokenTest(WebApplicationFactory<Startup> factory)
+ : base(factory)
{
- _testApp = new TestApplication(factory);
- _factory = _testApp.Factory;
+
}
- public void Dispose()
+ private static async Task<CreateTokenResponse> CreateUserTokenAsync(HttpClient client, string username, string password, int? expireOffset = null)
{
- _testApp.Dispose();
+ var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, Expire = expireOffset });
+ return response.Should().HaveStatusCode(200)
+ .And.HaveJsonBody<CreateTokenResponse>().Which;
}
public static IEnumerable<object[]> CreateToken_InvalidModel_Data()
@@ -46,7 +42,7 @@ namespace Timeline.Tests.IntegratedTests [MemberData(nameof(CreateToken_InvalidModel_Data))]
public async Task CreateToken_InvalidModel(string username, string password, int expire)
{
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
(await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest
{
Username = username,
@@ -65,7 +61,7 @@ namespace Timeline.Tests.IntegratedTests [MemberData(nameof(CreateToken_UserCredential_Data))]
public async void CreateToken_UserCredential(string username, string password)
{
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
var response = await client.PostAsJsonAsync(CreateTokenUrl,
new CreateTokenRequest { Username = username, Password = password });
response.Should().HaveStatusCode(400)
@@ -76,7 +72,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task CreateToken_Success()
{
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
var response = await client.PostAsJsonAsync(CreateTokenUrl,
new CreateTokenRequest { Username = MockUser.User.Username, Password = MockUser.User.Password });
var body = response.Should().HaveStatusCode(200)
@@ -88,7 +84,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task VerifyToken_InvalidModel()
{
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
(await client.PostAsJsonAsync(VerifyTokenUrl,
new VerifyTokenRequest { Token = null })).Should().BeInvalidModel();
}
@@ -96,7 +92,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task VerifyToken_BadFormat()
{
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
var response = await client.PostAsJsonAsync(VerifyTokenUrl,
new VerifyTokenRequest { Token = "bad token hahaha" });
response.Should().HaveStatusCode(400)
@@ -107,10 +103,10 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task VerifyToken_OldVersion()
{
- using var client = _factory.CreateDefaultClient();
- var token = (await client.CreateUserTokenAsync(MockUser.User.Username, MockUser.User.Password)).Token;
+ using var client = await CreateClientWithNoAuth();
+ var token = (await CreateUserTokenAsync(client, MockUser.User.Username, MockUser.User.Password)).Token;
- using (var scope = _factory.Server.Host.Services.CreateScope()) // UserService is scoped.
+ using (var scope = Factory.Server.Host.Services.CreateScope()) // UserService is scoped.
{
// create a user for test
var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
@@ -127,10 +123,10 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task VerifyToken_UserNotExist()
{
- using var client = _factory.CreateDefaultClient();
- var token = (await client.CreateUserTokenAsync(MockUser.User.Username, MockUser.User.Password)).Token;
+ using var client = await CreateClientWithNoAuth();
+ var token = (await CreateUserTokenAsync(client, MockUser.User.Username, MockUser.User.Password)).Token;
- using (var scope = _factory.Server.Host.Services.CreateScope()) // UserService is scoped.
+ using (var scope = Factory.Server.Host.Services.CreateScope()) // UserService is scoped.
{
var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
await userService.DeleteUser(MockUser.User.Username);
@@ -146,7 +142,7 @@ namespace Timeline.Tests.IntegratedTests //[Fact]
//public async Task VerifyToken_Expired()
//{
- // using (var client = _factory.CreateDefaultClient())
+ // using (var client = await CreateClientWithNoAuth())
// {
// // I can only control the token expired time but not current time
// // because verify logic is encapsuled in other library.
@@ -164,8 +160,8 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task VerifyToken_Success()
{
- using var client = _factory.CreateDefaultClient();
- var createTokenResult = await client.CreateUserTokenAsync(MockUser.User.Username, MockUser.User.Password);
+ using var client = await CreateClientWithNoAuth();
+ var createTokenResult = await CreateUserTokenAsync(client, MockUser.User.Username, MockUser.User.Password);
var response = await client.PostAsJsonAsync(VerifyTokenUrl,
new VerifyTokenRequest { Token = createTokenResult.Token });
response.Should().HaveStatusCode(200)
diff --git a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs index 2310fc66..25a7b675 100644 --- a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs @@ -15,27 +15,18 @@ using System.Net.Http.Headers; using System.Threading.Tasks;
using Timeline.Services;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Helpers.Authentication;
using Xunit;
using static Timeline.ErrorCodes.Http.Common;
using static Timeline.ErrorCodes.Http.UserAvatar;
namespace Timeline.Tests.IntegratedTests
{
- public class UserAvatarTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ public class UserAvatarTest : IntegratedTestBase
{
- private readonly TestApplication _testApp;
- private readonly WebApplicationFactory<Startup> _factory;
-
public UserAvatarTest(WebApplicationFactory<Startup> factory)
+ : base(factory)
{
- _testApp = new TestApplication(factory);
- _factory = _testApp.Factory;
- }
- public void Dispose()
- {
- _testApp.Dispose();
}
[Fact]
@@ -48,7 +39,7 @@ namespace Timeline.Tests.IntegratedTests Type = PngFormat.Instance.DefaultMimeType
};
- using (var client = await _factory.CreateClientAsUser())
+ using (var client = await CreateClientAsUser())
{
{
var res = await client.GetAsync("users/usernotexist/avatar");
@@ -57,7 +48,7 @@ namespace Timeline.Tests.IntegratedTests .Which.Code.Should().Be(Get.UserNotExist);
}
- var env = _factory.Server.Host.Services.GetRequiredService<IWebHostEnvironment>();
+ var env = Factory.Server.Host.Services.GetRequiredService<IWebHostEnvironment>();
var defaultAvatarData = await File.ReadAllBytesAsync(Path.Combine(env.ContentRootPath, "default-avatar.png"));
async Task GetReturnDefault(string username = "user")
@@ -239,7 +230,7 @@ namespace Timeline.Tests.IntegratedTests }
// Authorization check.
- using (var client = await _factory.CreateClientAsAdmin())
+ using (var client = await CreateClientAsAdmin())
{
{
var res = await client.PutByteArrayAsync("users/user/avatar", mockAvatar.Data, mockAvatar.Type);
@@ -266,7 +257,7 @@ namespace Timeline.Tests.IntegratedTests }
// bad username check
- using (var client = await _factory.CreateClientAsAdmin())
+ using (var client = await CreateClientAsAdmin())
{
{
var res = await client.GetAsync("users/u!ser/avatar");
diff --git a/Timeline.Tests/IntegratedTests/UserDetailTest.cs b/Timeline.Tests/IntegratedTests/UserDetailTest.cs index 8f2b6925..932c287e 100644 --- a/Timeline.Tests/IntegratedTests/UserDetailTest.cs +++ b/Timeline.Tests/IntegratedTests/UserDetailTest.cs @@ -1,38 +1,27 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
-using System;
using System.Net;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Threading.Tasks;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Helpers.Authentication;
-using Timeline.Tests.Mock.Data;
using Xunit;
namespace Timeline.Tests.IntegratedTests
{
- public class UserDetailTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ public class UserDetailTest : IntegratedTestBase
{
- private readonly TestApplication _testApp;
- private readonly WebApplicationFactory<Startup> _factory;
-
public UserDetailTest(WebApplicationFactory<Startup> factory)
+ : base(factory)
{
- _testApp = new TestApplication(factory);
- _factory = _testApp.Factory;
- }
- public void Dispose()
- {
- _testApp.Dispose();
}
[Fact]
public async Task PermissionTest()
{
{ // unauthorize
- using var client = _factory.CreateDefaultClient();
+ using var client = await CreateClientWithNoAuth();
{ // GET
var res = await client.GetAsync($"users/{MockUser.User.Username}/nickname");
res.Should().HaveStatusCode(HttpStatusCode.OK);
@@ -47,7 +36,7 @@ namespace Timeline.Tests.IntegratedTests }
}
{ // user
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
{ // GET
var res = await client.GetAsync($"users/{MockUser.User.Username}/nickname");
res.Should().HaveStatusCode(HttpStatusCode.OK);
@@ -70,7 +59,7 @@ namespace Timeline.Tests.IntegratedTests }
}
{ // user
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
{ // PUT other
var res = await client.PutStringAsync($"users/{MockUser.User.Username}/nickname", "aaa");
res.Should().HaveStatusCode(HttpStatusCode.OK);
@@ -88,7 +77,7 @@ namespace Timeline.Tests.IntegratedTests var url = $"users/{MockUser.User.Username}/nickname";
var userNotExistUrl = "users/usernotexist/nickname";
{
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
{
var res = await client.GetAsync(userNotExistUrl);
res.Should().HaveStatusCode(HttpStatusCode.NotFound)
@@ -134,7 +123,7 @@ namespace Timeline.Tests.IntegratedTests }
}
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
{
var res = await client.PutStringAsync(userNotExistUrl, "aaa");
res.Should().HaveStatusCode(HttpStatusCode.BadRequest)
diff --git a/Timeline.Tests/IntegratedTests/UserTest.cs b/Timeline.Tests/IntegratedTests/UserTest.cs index 7e99ddba..abfea18e 100644 --- a/Timeline.Tests/IntegratedTests/UserTest.cs +++ b/Timeline.Tests/IntegratedTests/UserTest.cs @@ -1,39 +1,28 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
-using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Helpers.Authentication;
-using Timeline.Tests.Mock.Data;
using Xunit;
using static Timeline.ErrorCodes.Http.User;
namespace Timeline.Tests.IntegratedTests
{
- public class UserTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ public class UserTest : IntegratedTestBase
{
- private readonly TestApplication _testApp;
- private readonly WebApplicationFactory<Startup> _factory;
-
public UserTest(WebApplicationFactory<Startup> factory)
+ : base(factory)
{
- _testApp = new TestApplication(factory);
- _factory = _testApp.Factory;
- }
- public void Dispose()
- {
- _testApp.Dispose();
}
[Fact]
public async Task Get_List_Success()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.GetAsync("users");
res.Should().HaveStatusCode(200)
.And.HaveJsonBody<UserInfo[]>()
@@ -43,7 +32,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Get_Single_Success()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.GetAsync("users/" + MockUser.User.Username);
res.Should().HaveStatusCode(200)
.And.HaveJsonBody<UserInfo>()
@@ -53,7 +42,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Get_InvalidModel()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.GetAsync("users/aaa!a");
res.Should().BeInvalidModel();
}
@@ -61,7 +50,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Get_Users_404()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.GetAsync("users/usernotexist");
res.Should().HaveStatusCode(404)
.And.HaveCommonBody()
@@ -79,7 +68,7 @@ namespace Timeline.Tests.IntegratedTests [MemberData(nameof(Put_InvalidModel_Data))]
public async Task Put_InvalidModel(string username, string password, bool? administrator)
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
(await client.PutAsJsonAsync("users/" + username,
new UserPutRequest { Password = password, Administrator = administrator }))
.Should().BeInvalidModel();
@@ -96,7 +85,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Put_Modiefied()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.PutAsJsonAsync("users/" + MockUser.User.Username, new UserPutRequest
{
Password = "password",
@@ -109,7 +98,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Put_Created()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
const string username = "puttest";
const string url = "users/" + username;
@@ -125,7 +114,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Patch_NotExist()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.PatchAsJsonAsync("users/usernotexist", new UserPatchRequest { });
res.Should().HaveStatusCode(404)
.And.HaveCommonBody()
@@ -135,7 +124,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Patch_InvalidModel()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.PatchAsJsonAsync("users/aaa!a", new UserPatchRequest { });
res.Should().BeInvalidModel();
}
@@ -143,7 +132,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Patch_Success()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
{
var res = await client.PatchAsJsonAsync("users/" + MockUser.User.Username,
new UserPatchRequest { Administrator = false });
@@ -155,7 +144,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Delete_InvalidModel()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var url = "users/aaa!a";
var res = await client.DeleteAsync(url);
res.Should().BeInvalidModel();
@@ -164,7 +153,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Delete_Deleted()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var url = "users/" + MockUser.User.Username;
var res = await client.DeleteAsync(url);
res.Should().BeDelete(true);
@@ -176,7 +165,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Delete_NotExist()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.DeleteAsync("users/usernotexist");
res.Should().BeDelete(false);
}
@@ -195,7 +184,7 @@ namespace Timeline.Tests.IntegratedTests [MemberData(nameof(Op_ChangeUsername_InvalidModel_Data))]
public async Task Op_ChangeUsername_InvalidModel(string oldUsername, string newUsername)
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
(await client.PostAsJsonAsync(changeUsernameUrl,
new ChangeUsernameRequest { OldUsername = oldUsername, NewUsername = newUsername }))
.Should().BeInvalidModel();
@@ -204,7 +193,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Op_ChangeUsername_UserNotExist()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.PostAsJsonAsync(changeUsernameUrl,
new ChangeUsernameRequest { OldUsername = "usernotexist", NewUsername = "newUsername" });
res.Should().HaveStatusCode(400)
@@ -215,7 +204,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Op_ChangeUsername_UserAlreadyExist()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
var res = await client.PostAsJsonAsync(changeUsernameUrl,
new ChangeUsernameRequest { OldUsername = MockUser.User.Username, NewUsername = MockUser.Admin.Username });
res.Should().HaveStatusCode(400)
@@ -223,15 +212,23 @@ namespace Timeline.Tests.IntegratedTests .Which.Code.Should().Be(Op.ChangeUsername.AlreadyExist);
}
+ private async Task TestLogin(string username, string password)
+ {
+ using var client = await CreateClientWithNoAuth();
+ var response = await client.PostAsJsonAsync("token/create", new CreateTokenRequest { Username = username, Password = password });
+ response.Should().HaveStatusCode(200)
+ .And.HaveJsonBody<CreateTokenResponse>();
+ }
+
[Fact]
public async Task Op_ChangeUsername_Success()
{
- using var client = await _factory.CreateClientAsAdmin();
+ using var client = await CreateClientAsAdmin();
const string newUsername = "hahaha";
var res = await client.PostAsJsonAsync(changeUsernameUrl,
new ChangeUsernameRequest { OldUsername = MockUser.User.Username, NewUsername = newUsername });
res.Should().HaveStatusCode(200);
- await client.CreateUserTokenAsync(newUsername, MockUser.User.Password);
+ await TestLogin(newUsername, MockUser.User.Password);
}
private const string changePasswordUrl = "userop/changepassword";
@@ -246,7 +243,7 @@ namespace Timeline.Tests.IntegratedTests [MemberData(nameof(Op_ChangePassword_InvalidModel_Data))]
public async Task Op_ChangePassword_InvalidModel(string oldPassword, string newPassword)
{
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
(await client.PostAsJsonAsync(changePasswordUrl,
new ChangePasswordRequest { OldPassword = oldPassword, NewPassword = newPassword }))
.Should().BeInvalidModel();
@@ -255,7 +252,7 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Op_ChangePassword_BadOldPassword()
{
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
var res = await client.PostAsJsonAsync(changePasswordUrl, new ChangePasswordRequest { OldPassword = "???", NewPassword = "???" });
res.Should().HaveStatusCode(400)
.And.HaveCommonBody()
@@ -265,13 +262,12 @@ namespace Timeline.Tests.IntegratedTests [Fact]
public async Task Op_ChangePassword_Success()
{
- using var client = await _factory.CreateClientAsUser();
+ using var client = await CreateClientAsUser();
const string newPassword = "new";
var res = await client.PostAsJsonAsync(changePasswordUrl,
new ChangePasswordRequest { OldPassword = MockUser.User.Password, NewPassword = newPassword });
res.Should().HaveStatusCode(200);
- await _factory.CreateDefaultClient() // don't use client above, because it sets authorization header
- .CreateUserTokenAsync(MockUser.User.Username, newPassword);
+ await TestLogin(MockUser.User.Username, newPassword);
}
}
}
diff --git a/Timeline.Tests/Services/UserAvatarServiceTest.cs b/Timeline.Tests/Services/UserAvatarServiceTest.cs index 033a5e90..2729aa6f 100644 --- a/Timeline.Tests/Services/UserAvatarServiceTest.cs +++ b/Timeline.Tests/Services/UserAvatarServiceTest.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using Timeline.Entities;
using Timeline.Services;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Mock.Data;
using Xunit;
namespace Timeline.Tests.Services
diff --git a/Timeline.Tests/Services/UserDetailServiceTest.cs b/Timeline.Tests/Services/UserDetailServiceTest.cs index bddb1494..9a869c89 100644 --- a/Timeline.Tests/Services/UserDetailServiceTest.cs +++ b/Timeline.Tests/Services/UserDetailServiceTest.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Timeline.Entities;
using Timeline.Services;
using Timeline.Tests.Helpers;
-using Timeline.Tests.Mock.Data;
using Xunit;
namespace Timeline.Tests.Services
diff --git a/Timeline.Tests/UsernameValidatorUnitTest.cs b/Timeline.Tests/UsernameValidatorUnitTest.cs index d02367be..e0f4633f 100644 --- a/Timeline.Tests/UsernameValidatorUnitTest.cs +++ b/Timeline.Tests/UsernameValidatorUnitTest.cs @@ -1,5 +1,6 @@ using FluentAssertions;
using Timeline.Models.Validation;
+using Timeline.Tests.Helpers;
using Xunit;
namespace Timeline.Tests
|