Skip to content

Add simplified assertions for PageResult and RedirectToPageResult #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions.Execution;
using FluentAssertions.Primitives;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;

namespace FluentAssertions.AspNetCore.Mvc
@@ -284,6 +285,27 @@ public ViewResultAssertions BeViewResult(string reason = "", params object[] rea
return new ViewResultAssertions(Subject as ViewResult);
}

/// <summary>
/// Asserts that the subject is a <see cref="PageResult"/>.
/// </summary>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
[CustomAssertion]
public PageResultAssertions BePageResult(string reason = "", params object[] reasonArgs)
{
Execute.Assertion
.BecauseOf(reason, reasonArgs)
.ForCondition(Subject is PageResult)
.FailWith(FailureMessages.CommonTypeFailMessage, typeof(PageResult), Subject.GetType());

return new PageResultAssertions(Subject as PageResult);
}

/// <summary>
/// Asserts that the subject is a <see cref="RedirectToActionResult"/>.
/// </summary>
@@ -305,6 +327,27 @@ public RedirectToActionResultAssertions BeRedirectToActionResult(string reason =
return new RedirectToActionResultAssertions(Subject as RedirectToActionResult);
}

/// <summary>
/// Asserts that the subject is a <see cref="RedirectToPageResult"/>.
/// </summary>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
[CustomAssertion]
public RedirectToPageResultAssertions BeRedirectToPageResult(string reason = "", params object[] reasonArgs)
{
Execute.Assertion
.BecauseOf(reason, reasonArgs)
.ForCondition(Subject is RedirectToPageResult)
.FailWith(FailureMessages.CommonTypeFailMessage, typeof(RedirectToPageResult), Subject.GetType());

return new RedirectToPageResultAssertions(Subject as RedirectToPageResult);
}

/// <summary>
/// Asserts that the subject is a <see cref="StatusCodeResult"/>.
/// </summary>
25 changes: 25 additions & 0 deletions src/FluentAssertions.AspNetCore.Mvc/PageResultAssertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using FluentAssertions.Primitives;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;

namespace FluentAssertions.AspNetCore.Mvc
{
/// <summary>
/// Contains a number of methods to assert that a <see cref="PageResult" /> is in the expected state.
/// </summary>
[DebuggerNonUserCode]
public class PageResultAssertions : ObjectAssertions
{
#region Public Constructors

/// <summary>
/// Initializes a new instance of the <see cref="PageResultAssertions" /> class.
/// </summary>
/// <param name="subject">The object to test assertion on</param>
public PageResultAssertions(PageResult subject) : base(subject)
{
}

#endregion Public Constructors
}
}
139 changes: 139 additions & 0 deletions src/FluentAssertions.AspNetCore.Mvc/RedirectToPageResultAssertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using FluentAssertions.Execution;
using FluentAssertions.Primitives;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Diagnostics;

namespace FluentAssertions.AspNetCore.Mvc
{
/// <summary>
/// Contains a number of methods to assert that a <see cref="RedirectToPageResult"/> is in the expected state.
/// </summary>
[DebuggerNonUserCode]
public class RedirectToPageResultAssertions : ObjectAssertions
{
/// <summary>
/// Initializes a new instance of the <see cref="RedirectToPageResultAssertions" /> class.
/// </summary>
public RedirectToPageResultAssertions(RedirectToPageResult subject) : base(subject) { }

private RedirectToPageResult RedirectToPageResultSubject => Subject as RedirectToPageResult;

/// <summary>
/// Asserts that the page name is the expected page.
/// </summary>
/// <param name="expectedPageName">The expected page.</param>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
public RedirectToPageResultAssertions WithPageName(string expectedPageName, string reason = "", params object[] reasonArgs)
{
string actualPageName = RedirectToPageResultSubject.PageName;

Execute.Assertion
.ForCondition(string.Equals(actualPageName, expectedPageName, StringComparison.OrdinalIgnoreCase))
.BecauseOf(reason, reasonArgs)
.WithDefaultIdentifier("RedirectToPageResult.PageName")
.FailWith(FailureMessages.CommonFailMessage, expectedPageName, actualPageName);

return this;
}

/// <summary>
/// Asserts that the fragment is the expected fragment.
/// </summary>
/// <param name="expectedFragment">The expected fragment.</param>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
public RedirectToPageResultAssertions WithFragment(string expectedFragment, string reason = "", params object[] reasonArgs)
{
string actualFragment = RedirectToPageResultSubject.Fragment;

Execute.Assertion
.ForCondition(string.Equals(actualFragment, expectedFragment, StringComparison.OrdinalIgnoreCase))
.BecauseOf(reason, reasonArgs)
.WithDefaultIdentifier("RedirectToPageResult.Fragment")
.FailWith(FailureMessages.CommonFailMessage, expectedFragment, actualFragment);

return this;
}

/// <summary>
/// Asserts that the redirect to page is permanent.
/// </summary>
/// <param name="expectedPermanent">Should the expected redirect be permanent.</param>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
public RedirectToPageResultAssertions WithPermanent(bool expectedPermanent, string reason = "", params object[] reasonArgs)
{
bool actualPermanent = RedirectToPageResultSubject.Permanent;

Execute.Assertion
.ForCondition(expectedPermanent == actualPermanent)
.BecauseOf(reason, reasonArgs)
.WithDefaultIdentifier("RedirectToPageResult.Permanent")
.FailWith(FailureMessages.CommonFailMessage, expectedPermanent, actualPermanent);

return this;
}

/// <summary>
/// Asserts that the redirect preserves the original request method.
/// </summary>
/// <param name="expectedPreserveMethod">Should the expected redirect preserve the original request method.</param>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
public RedirectToPageResultAssertions WithPreserveMethod(bool expectedPreserveMethod, string reason = "", params object[] reasonArgs)
{
bool actualPreserveMethod = RedirectToPageResultSubject.PreserveMethod;

Execute.Assertion
.ForCondition(expectedPreserveMethod == actualPreserveMethod)
.BecauseOf(reason, reasonArgs)
.WithDefaultIdentifier("RedirectToPageResult.PreserveMethod")
.FailWith(FailureMessages.CommonFailMessage, expectedPreserveMethod, actualPreserveMethod);

return this;
}

/// <summary>
/// Asserts that the redirect has the expected route value.
/// </summary>
/// <param name="key">The expected key.</param>
/// <param name="expectedValue">The expected value.</param>
/// <param name="reason">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="reasonArgs">
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
/// </param>
public RedirectToPageResultAssertions WithRouteValue(string key, object expectedValue, string reason = "", params object[] reasonArgs)
{
var subjectTyped = RedirectToPageResultSubject;

AssertionHelpers.AssertStringObjectDictionary(subjectTyped.RouteValues, "RedirectToPageResult.RouteValues", key, expectedValue, reason, reasonArgs);

return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions.AspNetCore.Mvc.Tests.Helpers;
using FluentAssertions.Mvc.Tests.Helpers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Routing;
using System;
using Xunit;
@@ -262,6 +263,26 @@ public void BeView_GivenNotView_ShouldFail()
.WithMessage(failureMessage);
}

[Fact]
public void BePage_GivenPage_ShouldPass()
{
ActionResult result = new PageResult();

result.Should().BePageResult();
}

[Fact]
public void BePage_GivenNotPage_ShouldFail()
{
ActionResult result = new RedirectResult("/");
var failureMessage = FailureMessageHelper.ExpectedContextTypeXButFoundYWithReason("result", typeof(PageResult), typeof(RedirectResult));

Action a = () => result.Should().BePageResult(Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(failureMessage);
}

[Fact]
public void BeStatusCodeResult_GivenStatusCodeResult_ShouldPass()
{
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using FluentAssertions.Mvc.Tests.Helpers;
using Microsoft.AspNetCore.Mvc;
using System;
using Xunit;

namespace FluentAssertions.AspNetCore.Mvc.Tests
{

public class RedirectToPageResultAssertions_Tests
{
public const string Reason = FailureMessageHelper.Reason;
public readonly static object[] ReasonArgs = FailureMessageHelper.ReasonArgs;

[Fact]
public void WithPageName_GivenExpectedPageName_ShouldPass()
{
var expectedPageName = "expectedPage";
RedirectToPageResult result = new RedirectToPageResult(expectedPageName, string.Empty, null);

result.Should().BeRedirectToPageResult()
.WithPageName(expectedPageName);
}

[Fact]
public void WithPageName_GivenUnexpectedPageName_ShouldFail()
{
RedirectToPageResult result = new RedirectToPageResult("someOtherPage", string.Empty, null);

Action a = () => result.Should().BeRedirectToPageResult()
.WithPageName("expectedPage", Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.PageName", "expectedPage", "someOtherPage"));
}

[Fact]
public void WithFragment_GivenExpectedFragment_ShouldPass()
{
var expectedFragment = "expectedFragment";
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, expectedFragment);

result.Should().BeRedirectToPageResult()
.WithFragment(expectedFragment);
}

[Fact]
public void WithFragment_GivenUnexpectedFragment_ShouldFail()
{
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, "someOtherFragment");

Action a = () => result.Should().BeRedirectToPageResult()
.WithFragment("expectedFragment", Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.Fragment", "expectedFragment", "someOtherFragment"));
}

[Fact]
public void WithPermanent_GivenExpectedValue_ShouldPass()
{
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, true);

result.Should().BeRedirectToPageResult()
.WithPermanent(true);
}

[Fact]
public void WithPermanent_GivenUnexpectedValue_ShouldFail()
{
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, true);

Action a = () => result.Should().BeRedirectToPageResult()
.WithPermanent(false, Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.Permanent", false, true));
}

[Fact]
public void WithPreservedMethod_GivenExpectedValue_ShouldPass()
{
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, true);

result.Should().BeRedirectToPageResult()
.WithPreserveMethod(true);
}

[Fact]
public void WithPreserveMethod_GivenUnexpectedValue_ShouldFail()
{
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, true);

Action a = () => result.Should().BeRedirectToPageResult()
.WithPreserveMethod(false, Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.PreserveMethod", false, true));
}

[Fact]
public void WithRouteValue_GivenKeyDoesntExist_ShouldFail()
{
var expectedKey = "expectedKey";
var failureMessage = FailureMessageHelper.ExpectedKeyButNotFound("RedirectToPageResult.RouteValues", expectedKey, "Val");

var routeValues = new { myKey = "MyValue" };
RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, routeValues);

Action a = () => result.Should().BeRedirectToPageResult().WithRouteValue(expectedKey, "Val", Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(failureMessage);
}

[Fact]
public void WithRouteValue_GivenExpectedKeyValuePair_ShouldPass()
{
var expectedKey = "expectedKey";
var expectedValue = "expectedValue";
var routeValues = new { expectedKey = expectedValue };

RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, routeValues);

result.Should().BeRedirectToPageResult().WithRouteValue(expectedKey, expectedValue);
}

[Fact]
public void HaveValue_GivenUnexpectedKeyValuePair_ShouldFail()
{
var expectedKey = "expectedKey";
var expectedValue = "expectedValue";
var routeValues = new { expectedKey = "someOtherValue" };
var failureMessage = FailureMessageHelper.ExpectedAtKeyValueXButFoundY("RedirectToPageResult.RouteValues", expectedKey, expectedValue, "someOtherValue");

RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, routeValues);
Action a = () => result.Should().BeRedirectToPageResult().WithRouteValue(expectedKey, expectedValue, Reason, ReasonArgs);

a.Should().Throw<Exception>()
.WithMessage(failureMessage);
}
}
}