Skip to content

Commit 44d8b65

Browse files
committed
Make GeneratePath easier to use
1 parent 9fe8336 commit 44d8b65

9 files changed

Lines changed: 29 additions & 63 deletions

File tree

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<ItemGroup>
77
<!-- Static code analysis -->
88
<PackageVersion Include="AngleSharp" Version="1.6.0" />
9+
<PackageVersion Include="JetBrains.Annotations" Version="2026.2.0" />
910
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="10.0.10" />
1011
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.10" />
1112
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.22.0" />

tests/SchoolAccount.IntegrationTests/Common/SchoolAccountWebApplicationFactory.cs

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Reflection;
2+
using JetBrains.Annotations;
23
using Microsoft.AspNetCore.Authentication;
34
using Microsoft.AspNetCore.Authentication.Cookies;
45
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
@@ -34,30 +35,14 @@ public HttpClient CreateUnauthorisedClient(
3435
return CreateClient<MockOidcHandler>(additionalConfigurableServices, options);
3536
}
3637

37-
public string GeneratePath<T>(string action, object? query = null)
38-
where T : ControllerBase
39-
{
40-
if (string.IsNullOrWhiteSpace(action))
41-
{
42-
return null;
43-
}
44-
45-
var controllerType = typeof(T);
46-
return controllerType
47-
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
48-
.Any(x => x.Name == action)
49-
? GeneratePath(GetControllerRoute(controllerType), action, query)
50-
: throw new ArgumentException(
51-
$"Action {action} not found on controller {controllerType.Name}"
52-
);
53-
}
54-
55-
public string GeneratePath(string controller, string action, object? query = null)
38+
public string GeneratePath(
39+
[AspMvcController] string controller,
40+
[AspMvcAction] string action,
41+
[AspMvcModelType] object? query = null
42+
)
5643
{
5744
using var scope = Services.CreateScope();
58-
5945
var generator = scope.ServiceProvider.GetRequiredService<LinkGenerator>();
60-
6146
return generator.GetPathByAction(action, controller.Replace("Controller", ""), query);
6247
}
6348

@@ -105,16 +90,4 @@ private HttpClient CreateClient<THandler>(
10590
}
10691
);
10792
}
108-
109-
private static string GetControllerRoute(Type controllerType)
110-
{
111-
var template = controllerType.GetCustomAttribute<RouteAttribute>()?.Template;
112-
113-
if (template?.Contains('{') == true && template?.Contains('}') == true)
114-
{
115-
template = null;
116-
}
117-
118-
return template ?? controllerType.Name.Replace(nameof(Controller), string.Empty);
119-
}
12093
}

tests/SchoolAccount.IntegrationTests/Features/Account/LoggedOutActionTests.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,15 @@ public async Task Ensure_an_authenticated_user_accessing_LoggedOut_are_redirecte
1616
{
1717
// Arrange
1818
var client = factory.CreateUnauthorisedClient();
19-
var requestUri = factory.GeneratePath<AccountController>(
20-
nameof(AccountController.LoggedOut)
21-
);
19+
var requestUri = factory.GeneratePath("Account", "LoggedOut");
2220

2321
// Act
2422
var response = await client.GetAsync(requestUri, TestContext.Current.CancellationToken);
2523

2624
// Assert
2725
response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
2826
response.Headers.Location?.OriginalString.ShouldStartWith(
29-
factory.GeneratePath<StartController>(nameof(StartController.Start))
27+
factory.GeneratePath("Start", "Start")
3028
);
3129
}
3230

@@ -51,9 +49,7 @@ public async Task Ensure_LoggedOut_clears_a_users_session()
5149
services.AddSingleton(mockContextAssessor);
5250
});
5351

54-
var requestUri = factory.GeneratePath<AccountController>(
55-
nameof(AccountController.LoggedOut)
56-
);
52+
var requestUri = factory.GeneratePath("Account", "LoggedOut");
5753

5854
// Act
5955
await client.GetAsync(requestUri, TestContext.Current.CancellationToken);

tests/SchoolAccount.IntegrationTests/Features/Account/LoginActionTests.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public async Task Unauthorised_users_are_redirected_to_DSI()
1414
{
1515
// Arrange
1616
var client = factory.CreateUnauthorisedClient();
17-
var requestUri = factory.GeneratePath<AccountController>(nameof(AccountController.Login));
17+
var requestUri = factory.GeneratePath("Account", "Login");
1818

1919
// Act
2020
using var content = new StringContent(string.Empty);
@@ -52,7 +52,7 @@ public async Task Authorised_users_are_redirected_to_the_dashboard()
5252
// Assert
5353
response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
5454
response.Headers.Location?.OriginalString.ShouldEndWith(
55-
$"{factory.GeneratePath<DashboardController>(nameof(DashboardController.Dashboard))}"
55+
$"{factory.GeneratePath("Dashboard", "Dashboard")}"
5656
);
5757
}
5858

@@ -61,8 +61,9 @@ public async Task Non_local_urls_returns_problem_response()
6161
{
6262
// Arrange
6363
var client = factory.CreateAuthorisedClient();
64-
var requestUri = factory.GeneratePath<AccountController>(
65-
nameof(AccountController.Login),
64+
var requestUri = factory.GeneratePath(
65+
"Account",
66+
"Login",
6667
new { returnUrl = "https://www.google.com" }
6768
);
6869

@@ -83,14 +84,10 @@ public async Task Local_urls_returns_success_response()
8384
{
8485
// Arrange
8586
var client = factory.CreateAuthorisedClient();
86-
var requestUri = factory.GeneratePath<AccountController>(
87-
nameof(AccountController.Login),
88-
new
89-
{
90-
returnUrl = factory.GeneratePath<DashboardController>(
91-
nameof(DashboardController.Dashboard)
92-
),
93-
}
87+
var requestUri = factory.GeneratePath(
88+
"Account",
89+
"Login",
90+
new { returnUrl = factory.GeneratePath("Dashboard", "Dashboard") }
9491
);
9592

9693
// Act

tests/SchoolAccount.IntegrationTests/Features/Account/LogoutActionTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public async Task Authorised_users_can_sign_out()
1414
{
1515
// Arrange
1616
var client = factory.CreateAuthorisedClient(options: ClientOptions.AllowRedirects);
17-
var requestUri = factory.GeneratePath<AccountController>(nameof(AccountController.Logout));
17+
var requestUri = factory.GeneratePath("Account", "Logout");
1818

1919
// Act
2020
using var content = new StringContent(string.Empty);
@@ -36,7 +36,7 @@ public async Task Unauthorised_users_accessing_sign_out_get_redirected_to_start_
3636
{
3737
// Arrange
3838
var client = factory.CreateUnauthorisedClient(options: ClientOptions.AllowRedirects);
39-
var requestUri = factory.GeneratePath<AccountController>(nameof(AccountController.Logout));
39+
var requestUri = factory.GeneratePath("Account", "Logout");
4040

4141
// Act
4242
using var content = new StringContent(string.Empty);
@@ -49,7 +49,7 @@ public async Task Unauthorised_users_accessing_sign_out_get_redirected_to_start_
4949
// Assert
5050
response.StatusCode.ShouldBe(HttpStatusCode.OK);
5151
response.Headers.Location?.OriginalString.ShouldEndWith(
52-
factory.GeneratePath<StartController>(nameof(StartController.Start))
52+
factory.GeneratePath("Start", "Start")
5353
);
5454
}
5555
}

tests/SchoolAccount.IntegrationTests/Features/CrossCutting/AnonymousEndpointGuardrailTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ public class AnonymousEndpointGuardrailTests(SchoolAccountWebApplicationFactory<
1313
// Adding a new anonymous endpoint should be a conscious, reviewed decision, not an accident.
1414
private readonly HashSet<string> _allowlistedAnonymousEndpoints =
1515
[
16-
factory.GeneratePath<StartController>(nameof(StartController.Start)),
17-
factory.GeneratePath<AccountController>(nameof(AccountController.Login)),
18-
factory.GeneratePath<AccountController>(nameof(AccountController.Logout)),
19-
factory.GeneratePath<AccountController>(nameof(AccountController.LoggedOut)),
16+
factory.GeneratePath("Start", "Start"),
17+
factory.GeneratePath("Account", "Login"),
18+
factory.GeneratePath("Account", "Logout"),
19+
factory.GeneratePath("Account", "LoggedOut"),
2020
];
2121

2222
private static readonly string[] _staticAssetFileExtensions =

tests/SchoolAccount.IntegrationTests/Features/Dashboard/DashboardControllerTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ public async Task Ensure_that_the_dashboard_controller_returns_correct_user_name
4444
.Handle(Arg.Any<GetTimeSpecificHelloQuery>(), Arg.Any<CancellationToken>())
4545
.Returns(Result.Success(stubbedGetSpecificHelloResponse));
4646

47-
var pageUri = _factory.GeneratePath<DashboardController>(
48-
nameof(DashboardController.Dashboard)
49-
);
47+
var pageUri = _factory.GeneratePath("Dashboard", "Dashboard");
5048

5149
// Act
5250
var response = await _client.GetAsync(pageUri, TestContext.Current.CancellationToken);

tests/SchoolAccount.IntegrationTests/Features/Start/StartControllerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public StartControllerTests(SchoolAccountWebApplicationFactory<Program> factory)
3535
public async Task Ensure_that_the_start_controller_returns_a_successful_result()
3636
{
3737
// Arrange
38-
var pageUri = _factory.GeneratePath<StartController>(string.Empty);
38+
var pageUri = _factory.GeneratePath("Start", "Start");
3939

4040
// Act
4141
var response = await _client.GetAsync(pageUri, TestContext.Current.CancellationToken);

tests/SchoolAccount.IntegrationTests/SchoolAccount.IntegrationTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
<ItemGroup>
1111
<PackageReference Include="AngleSharp" />
12+
<PackageReference Include="JetBrains.Annotations" />
1213
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
1314
<PackageReference Include="NSubstitute" />
1415
<PackageReference Include="Shouldly" />

0 commit comments

Comments
 (0)