Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
ebc8530
Created fake helper classes to assist with testing Blazor authenticat…
DarthPedro Jun 15, 2020
16b7585
Added extension methods to add appropriate authentication/authorizati…
DarthPedro Jun 16, 2020
f92a850
Added component tests that use AuthorizeView and the BUnit authorizat…
DarthPedro Jun 16, 2020
80baed4
Updated changelog and minor cleanup for SimpleAuthView and test.
DarthPedro Jun 16, 2020
35b9b5c
Added placeholders for AuthenticationStateProvider and IAuthorization…
DarthPedro Jun 16, 2020
ffbc120
Merge pull request #1 from egil/dev
DarthPedro Jun 16, 2020
308914a
committing this to be able to switch
DarthPedro Jun 16, 2020
f6f4471
Created fake helper classes to assist with testing Blazor authenticat…
DarthPedro Jun 15, 2020
f804a1e
Added extension methods to add appropriate authentication/authorizati…
DarthPedro Jun 16, 2020
b0931ec
Added component tests that use AuthorizeView and the BUnit authorizat…
DarthPedro Jun 16, 2020
6deb8c5
Updated changelog and minor cleanup for SimpleAuthView and test.
DarthPedro Jun 16, 2020
908d219
Added placeholders for AuthenticationStateProvider and IAuthorization…
DarthPedro Jun 16, 2020
7316fb0
Merge branch 'dev-authorization-fakes' of https://github.com/DarthPed…
DarthPedro Jun 16, 2020
6ef2e83
Added documentation for fake authorization services and how to use them.
DarthPedro Jun 17, 2020
a316b3e
Fixed code formatting in documentation.
DarthPedro Jun 17, 2020
e753deb
Update docs/site/docs/mocking/mocking-auth.md
DarthPedro Jun 17, 2020
bd1dcbb
Update src/bunit.web/TestDoubles/Authorization/FakeAuthenticationStat…
DarthPedro Jun 17, 2020
94e1d77
Update docs/site/docs/mocking/mocking-auth.md
DarthPedro Jun 17, 2020
402b38d
Update src/bunit.web.tests/TestDoubles/Authorization/FakeAuthorizatio…
DarthPedro Jun 17, 2020
fa5d230
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplay.razor
DarthPedro Jun 17, 2020
9f4b4fe
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
8defb66
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
b28ad7b
Update src/bunit.web.tests/TestDoubles/Authorization/SimpleAuthView.r…
DarthPedro Jun 17, 2020
45280c6
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
2f8c99e
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
94f8035
Merge pull request #3 from egil/dev
DarthPedro Jun 17, 2020
9ed6e40
Merge branch 'dev' of https://github.com/DarthPedro/bUnit into dev
DarthPedro Jun 17, 2020
9bad52b
Created fake helper classes to assist with testing Blazor authenticat…
DarthPedro Jun 15, 2020
e49a77e
Added extension methods to add appropriate authentication/authorizati…
DarthPedro Jun 16, 2020
534144c
Added component tests that use AuthorizeView and the BUnit authorizat…
DarthPedro Jun 16, 2020
2e86791
Updated changelog and minor cleanup for SimpleAuthView and test.
DarthPedro Jun 16, 2020
084b0f1
Added placeholders for AuthenticationStateProvider and IAuthorization…
DarthPedro Jun 16, 2020
a3929c4
Update src/bunit.web/TestDoubles/Authorization/FakeAuthenticationStat…
DarthPedro Jun 17, 2020
c8cf267
Update src/bunit.web.tests/TestDoubles/Authorization/FakeAuthorizatio…
DarthPedro Jun 17, 2020
232efd9
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplay.razor
DarthPedro Jun 17, 2020
1d1a577
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
05799b2
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
d979d30
Update src/bunit.web.tests/TestDoubles/Authorization/SimpleAuthView.r…
DarthPedro Jun 17, 2020
cb0442d
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
4dea2f4
Update src/bunit.web.tests/TestDoubles/Authorization/LoginDisplayTest.cs
DarthPedro Jun 17, 2020
2b6939c
committing merge with dev doc changes
DarthPedro Jun 17, 2020
99bf847
Removed this prefixes from usage in code.
DarthPedro Jun 17, 2020
d4eda28
Rename SimpleAuthViewTest to AuthorizationTests to better describe wh…
DarthPedro Jun 17, 2020
086dbc6
Added AuthorizationState enum to encapsulate the states. Changed API …
DarthPedro Jun 17, 2020
ecb1f9a
Renamed FakeAuthorizationExtensions.AddAuthorization to AddTestAuthor…
DarthPedro Jun 17, 2020
50306e5
Replaced FakeAuthorizationService.NextResult to be CurrentState with …
DarthPedro Jun 17, 2020
561575c
Added simplifying methods to FakeAuthorizationExtensions to UpdateTes…
DarthPedro Jun 17, 2020
6579e98
Added factory method to simplify creating ClaimsPrincipal when needed.
DarthPedro Jun 17, 2020
e9e95d9
Update docs/site/docs/test-doubles/faking-auth.md
DarthPedro Jun 17, 2020
c6f69b1
Update docs/site/docs/test-doubles/faking-auth.md
DarthPedro Jun 17, 2020
be481cd
Update src/bunit.web/TestDoubles/Authorization/MissingFakeAuthorizati…
DarthPedro Jun 17, 2020
821573e
Fix build failure caused by IList property with a setter.
DarthPedro Jun 17, 2020
82bd35d
Moved SimpleAuthTest to bunit.testassets project. Fixed tests to refe…
DarthPedro Jun 17, 2020
3f6c598
Add an explicit SetAuthorizationState to FakeAuthorizationService.
DarthPedro Jun 18, 2020
ffcae94
Hide the CurrentState property because it's an implementation detail.
DarthPedro Jun 18, 2020
11629f6
Made policy scheme name a settable property with a default to TestSch…
DarthPedro Jun 18, 2020
97dd96f
Created an AuthorizationAdaptor to wrap some of the auth services and…
DarthPedro Jun 18, 2020
e707b5e
Renamed AuthorizationAdaptor to TestAuthorizationContext and minor cl…
DarthPedro Jun 18, 2020
6ac02d1
Changed Roles properties to be non-nullable in TestAuthorizationConte…
DarthPedro Jun 18, 2020
a5f09a3
Renamed TestAuthorizationContext methods to SetAuthorized and SetNotA…
DarthPedro Jun 18, 2020
2e513d2
Update CHANGELOG.md with PR comments
DarthPedro Jun 18, 2020
bb9448a
Minor clean ups from PR comments.
DarthPedro Jun 18, 2020
55e34f7
Added check to property setters in FakeIdentity and FakeAuthorization…
DarthPedro Jun 18, 2020
cd70c01
Exposed AuthorizeCalls through TestAuthorizationContext for callers t…
DarthPedro Jun 18, 2020
08b6405
Small style tweaks to code, spelling, etc.
egil Jun 19, 2020
295a3b1
Merge branch 'dev' into dev-authorization-fakes
egil Jun 19, 2020
a189d58
Added back .Render() to test removed during experiments
egil Jun 19, 2020
06f3faa
Additional simplifications of code, update to changelog
egil Jun 19, 2020
b7171ce
Fixed tests and code that broke during refactor
egil Jun 19, 2020
0862a8f
Added empty string check to PolicySchemeName. Removed AuthorizeCalls
DarthPedro Jun 19, 2020
a818c2f
Added documentation sample code to the bunit.docs.samples project. Up…
DarthPedro Jun 19, 2020
3e4b04d
Merge branch 'dev' into dev-authorization-fakes
egil Jun 20, 2020
ac59ecf
Made roles list in SetAuthorized a params string[] roles, making it e…
DarthPedro Jun 20, 2020
c67cfd4
Added TestAuthorizationContext.SetAuthorizationPolicies as way for ca…
DarthPedro Jun 20, 2020
e206bf0
Fix up sample build break.
DarthPedro Jun 20, 2020
a944488
Added SimpleAuthViewWithPolicy component to validate testing with Aut…
DarthPedro Jun 20, 2020
a88b2aa
Added sample code and unit tests for using AuthorizeView with Policy.
DarthPedro Jun 20, 2020
4f5fc66
changed role names, and removed ConfigureAwait calls from test classes.
DarthPedro Jun 22, 2020
10fdc3c
Made CreatePrincipal internal
DarthPedro Jun 22, 2020
ed87615
Added SetRoles method, and made the TestAuthorizationContext methods …
DarthPedro Jun 22, 2020
4b518bd
Updated samples to the TestAuthorizationContext api changes.
DarthPedro Jun 22, 2020
26a21ac
Updated docs to match the style of the other pages
egil Jun 24, 2020
92b06e3
Added docs samples
egil Jun 24, 2020
41725b4
Tests (which breaks) for missing or invalid roles and policies
egil Jun 24, 2020
4c65bb1
removed src/bunit.testassets/SampleComponents/SimpleWithJsRuntimeDep.…
egil Jun 24, 2020
2851cdb
Readded SimpleWithJSRuntimeDep.razor
egil Jun 24, 2020
5bfd207
Fix FakeAuthorizationService to validate checks for policies and role…
DarthPedro Jun 24, 2020
7e6081e
Added SetAuthorizing method and state implementation to get Authorize…
DarthPedro Jun 24, 2020
315ea0f
Added TestAuthorizationContext.SetClaims and implementation in servic…
DarthPedro Jun 24, 2020
38c8aef
Clean up from PR comments.
DarthPedro Jun 24, 2020
97953dc
Added negative test for AuthorizeView without defined claims.
DarthPedro Jun 24, 2020
4bb2386
Update docs/samples/components/UserInfo.razor
DarthPedro Jun 24, 2020
be8f9dd
Changed code to remove null pointer exception if authorizing state wa…
egil Jun 25, 2020
c561fe1
Docs: added authorizing example to tests, fixed spelling and gramma
egil Jun 25, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,43 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added
List of new features.

#### Authorization Fakes
Added authentication/authorization fake services to make it easy to test Blazor components that use authorization either through code or the AuthorizeView component.
You just need to call the AddAuthorization method on your TestContext.Services collection.

First, define your component that uses AuthorizeView to render differently based on the user's authorization state.
```
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization

<CascadingAuthenticationState>
<AuthorizeView>
<Authorized>
Authorized!
</Authorized>
<NotAuthorized>
Not authorized?
</NotAuthorized>
</AuthorizeView>
</CascadingAuthenticationState>
```
Then, define your test method to specify the authorization state with a user name, and run your test.
```c#
[Fact(DisplayName = "AuthorizeView with authenticated and authorized user")]
public void Test002()
{
// arrange
using var ctx = new TestContext();
ctx.Services.AddAuthorization("TestUser", true);

// act
var cut = ctx.RenderComponent<SimpleAuthView>();

// assert
cut.MarkupMatches("Authorized!");
}
```

### Changed
List of changes in existing functionality.

Expand Down
128 changes: 126 additions & 2 deletions docs/site/docs/mocking/mocking-auth.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,132 @@
---
---
uid: mocking-auth
title: Mocking Blazor's Authorization
---

# Mocking Blazor's Authorization

https://github.com/egil/bunit/issues/135
https://github.com/egil/bunit/issues/135

When testing Blazor components that require authentication and authorization, you need to set up enough of the services and behavior to work with the Blazor AuthorizeView, CascadingAuthenticationState, and AuthorizeRouteView.

You can use AuthorizeView in a component to show different content based on the user's authentication/authorization state. To set your component up for testing, you can do the following:

```c#
@using Microsoft.AspNetCore.Components.Authorization

<CascadingAuthenticationState>
<AuthorizeView>
<Authorized>
Authorized!
</Authorized>
<NotAuthorized>
Not authorized?
</NotAuthorized>
</AuthorizeView>
</CascadingAuthenticationState>
```

To easily test this type of component, bUnit has some test services that help. You will need to add these services to your test context before you render and run your tests.

The following code tests the component with an unauthenticated user. To setup an authenticated user, just call AddAuthorization with no parameters.

```c#
[Fact(DisplayName = "AuthorizeView with unauthenticated user")]
public void Test001()
{
// arrange
using var ctx = new TestContext();
ctx.Services.AddAuthorization();

// act
var cut = ctx.RenderComponent<SimpleAuthView>();

// assert
cut.MarkupMatches("Not authorized?");
}
```

Now we can test with an authenticated and authorized user by calling AddAuthorization with a user name and authorization flag.

```c#
[Fact(DisplayName = "AuthorizeView with authenticated and authorized user")]
public void Test002()
{
// arrange
using var ctx = new TestContext();
ctx.Services.AddAuthorization("TestUser", true);

// act
var cut = ctx.RenderComponent<SimpleAuthView>();

// assert
cut.MarkupMatches("Authorized!");
}
```

Finally we can test with an authenticated and unauthorized user in the code below.

```c#
[Fact(DisplayName = "AuthorizeView with authenticated but unauthorized user")]
public void Test003()
{
// arrange
using var ctx = new TestContext();
ctx.Services.AddAuthorization("TestUser", false);

// act
var cut = ctx.RenderComponent<SimpleAuthView>();

// assert
cut.MarkupMatches("Not authorized?");
}
```

In addition to using these services with AuthorizeView, you can also inject the services into your component and call them in your C# code.

```c#
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject AuthenticationStateProvider AuthenticationStateProvider

<p>Test Component</p>

@if (isAuthenticated)
{
<p>User: @userName</p>
}

@code{
bool isAuthenticated = false;
string userName;

protected override async Task OnInitializedAsync()
{
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync().ConfigureAwait(false);
if (state != null)
{
this.isAuthenticated = state.User.Identity.IsAuthenticated;
this.userName = state.User.Identity.Name;
}
}
}
```

Then you can write a similar test as the ones above.

```c#
[Fact(DisplayName = "Use AuthenticationStateProvider service with authenticated and authorized user")]
public void Test004()
{
// arrange
using var ctx = new TestContext();
ctx.Services.AddAuthorization("TestUserName", true);

// act
var cut = ctx.RenderComponent<TestComponent>();

// assert
Assert.Contains("<p>User: TestUserName</p>", cut.Markup, StringComparison.InvariantCulture);
}
```

That is all you need to support authorization and authentication testing in bUnit.
3 changes: 0 additions & 3 deletions src/bunit.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{785D
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.template", "bunit.template\bunit.template.csproj", "{58FB9C26-7170-426C-ACE8-A98237710CDB}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.template", "bunit.template\bunit.template.csproj", "{56F7777C-38B1-4183-98A1-3D8D207A19BB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -92,8 +91,6 @@ Global
{58FB9C26-7170-426C-ACE8-A98237710CDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58FB9C26-7170-426C-ACE8-A98237710CDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58FB9C26-7170-426C-ACE8-A98237710CDB}.Release|Any CPU.Build.0 = Release|Any CPU
{56F7777C-38B1-4183-98A1-3D8D207A19BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56F7777C-38B1-4183-98A1-3D8D207A19BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;

namespace Bunit.TestDoubles.Authorization
{
public class FakeAuthenticationStateProviderTest
{
[Fact(DisplayName = "Create authenticated AuthenticationState")]
public async Task Test001()
{
// arrange
var roles = new List<string> { "User" };

// act
var authProvider = new FakeAuthenticationStateProvider("TestUser", roles);
var authState = await authProvider.GetAuthenticationStateAsync();

// assert
Assert.NotNull(authState.User);
Assert.NotNull(authState.User.Identity);
Assert.Equal("TestUser", authState.User.Identity.Name);
Assert.True(authState.User.Identity.IsAuthenticated);
}

[Fact(DisplayName = "Create unauthenticated AuthenticationState")]
public async Task Test002()
{
// act
var authProvider = new FakeAuthenticationStateProvider();
var authState = await authProvider.GetAuthenticationStateAsync();

// assert
Assert.NotNull(authState.User);
Assert.NotNull(authState.User.Identity);
Assert.Null(authState.User.Identity.Name);
Assert.False(authState.User.Identity.IsAuthenticated);
}

[Fact(DisplayName = "Switch AuthenticationState from unauthenticated to authenticated.")]
public async Task Test003()
{
// arrange
var authProvider = new FakeAuthenticationStateProvider();
var stateChangeHandled = false;
authProvider.AuthenticationStateChanged += e => stateChangeHandled = true;

var newState = FakeAuthenticationStateProvider.CreateAuthenticationState("NewUser");

// act
authProvider.TriggerAuthenticationStateChanged(newState);
var authState = await authProvider.GetAuthenticationStateAsync();

// assert
Assert.True(stateChangeHandled);
Assert.NotNull(authState.User);
Assert.NotNull(authState.User.Identity);
Assert.Equal("NewUser", authState.User.Identity.Name);
Assert.True(authState.User.Identity.IsAuthenticated);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Bunit.TestDoubles.Authorization
{
public class FakeAuthorizationExtensionsTest
{
[Fact(DisplayName = "Register Authorization services with authenticated and authorized user.")]
public async Task Test001()
{
// arrange
using var sp = new TestServiceProvider();
var roles = new List<string> { "User" };
var principal = new ClaimsPrincipal(
new FakePrincipal { Identity = new FakeIdentity { Name = "DarthPedro" }, Roles = roles });

// act
sp.AddAuthorization("DarthPedro", true, roles);

var authProvider = sp.GetRequiredService<AuthenticationStateProvider>();
var authState = await authProvider.GetAuthenticationStateAsync();

var authService = sp.GetRequiredService<IAuthorizationService>();
var authResult = await authService.AuthorizeAsync(principal, "testResource", "testPolicy");

// assert
Assert.NotNull(authState.User);
Assert.NotNull(authState.User.Identity);
Assert.Equal("DarthPedro", authState.User.Identity.Name);
Assert.True(authState.User.Identity.IsAuthenticated);
Assert.True(authResult.Succeeded);
}

[Fact(DisplayName = "Register Authorization services with authenticated but unauthorized user.")]
public async Task Test002()
{
// arrange
using var sp = new TestServiceProvider();
var principal = new ClaimsPrincipal(
new FakePrincipal { Identity = new FakeIdentity { Name = "DarthPedro" } });

// act
sp.AddAuthorization("DarthPedro", false);

var authProvider = sp.GetRequiredService<AuthenticationStateProvider>();
var authState = await authProvider.GetAuthenticationStateAsync();

var authService = sp.GetRequiredService<IAuthorizationService>();
var authResult = await authService.AuthorizeAsync(principal, "testResource", "testPolicy");

// assert
Assert.NotNull(authState.User);
Assert.NotNull(authState.User.Identity);
Assert.Equal("DarthPedro", authState.User.Identity.Name);
Assert.True(authState.User.Identity.IsAuthenticated);
Assert.False(authResult.Succeeded);
}

[Fact(DisplayName = "Register Authorization services with unauthenticated user.")]
public async Task Test003()
{
// arrange
using var sp = new TestServiceProvider();
var principal = new ClaimsPrincipal(
new FakePrincipal { Identity = new FakeIdentity { Name = "DarthPedro" } });

// act
sp.AddAuthorization();

var authProvider = sp.GetRequiredService<AuthenticationStateProvider>();
var authState = await authProvider.GetAuthenticationStateAsync();

var authService = sp.GetRequiredService<IAuthorizationService>();
var authResult = await authService.AuthorizeAsync(principal, "testResource", "testPolicy");

// assert
Assert.NotNull(authState.User);
Assert.NotNull(authState.User.Identity);
Assert.Null(authState.User.Identity.Name);
Assert.False(authState.User.Identity.IsAuthenticated);
Assert.False(authResult.Succeeded);
}
}
}
Loading