Skip to content

Commit 0357e47

Browse files
authoredNov 1, 2020
Merge pull request #23 from faddiv/master
Version 3.2
2 parents 4637031 + 3f7d785 commit 0357e47

File tree

7 files changed

+228
-10
lines changed

7 files changed

+228
-10
lines changed
 

‎samples/FluentAssertions.AspNetCore.Mvc.Sample.Tests/ProductController_Tests.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using FluentAssertions.AspNetCore.Mvc.Sample.Controllers;
22
using Microsoft.AspNetCore.Mvc;
3-
using System;
43
using Xunit;
54

65
namespace FluentAssertions.AspNetCore.Mvc.Sample.Tests
@@ -25,8 +24,10 @@ public void GetActionResultOfT_OnFalse_Returns_Data()
2524

2625
var result = controller.GetActionResultOfT(model, returnError);
2726

28-
result.Should().BeConvertibleTo<ObjectResult>()
29-
.And.Value.Should().BeSameAs(model);
27+
result.Should().BeObjectResult()
28+
.WithValue(model) // Equals check
29+
.WithValueEquivalentTo(model) // Equivalency check
30+
.WithValueMatch<Models.ProductViewModel>(m => m.Id == 1); // match check.
3031
}
3132

3233
[Fact]

‎src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public FileStreamResultAssertions BeFileStreamResult(string reason = "", params
139139
}
140140

141141
/// <summary>
142-
/// Asserts that the subject is an <see cref="FileStreamResult"/>.
142+
/// Asserts that the subject is an <see cref="PhysicalFileResult"/>.
143143
/// </summary>
144144
/// <param name="reason">
145145
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion

‎src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertionsOfTValue.cs

+20-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,25 @@ public AndWhichConstraint<ActionResultAssertions<TValue>, TActionResult> BeConve
7979

8080
return new AndWhichConstraint<ActionResultAssertions<TValue>, TActionResult>(this, (TActionResult)convertResult);
8181
}
82+
83+
/// <summary>
84+
/// Asserts that the <see cref="ActionResult{TValue}.Result"/> is type of <see cref="ObjectResult"/>.
85+
/// </summary>
86+
/// <param name="reason">
87+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
88+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
89+
/// </param>
90+
/// <param name="reasonArgs">
91+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
92+
/// </param>
93+
[CustomAssertion]
94+
public ObjectResultAssertions BeObjectResult(string reason = "", params object[] reasonArgs)
95+
{
96+
var result = BeConvertibleTo<ObjectResult>(reason, reasonArgs).Which;
97+
98+
return new ObjectResultAssertions(result);
99+
}
100+
101+
#endregion Public Methods
82102
}
83-
#endregion Public Methods
84103
}

‎src/FluentAssertions.AspNetCore.Mvc/FluentAssertions.AspNetCore.Mvc.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<Copyright>Copyright 2018</Copyright>
66
<AssemblyTitle>Fluent Assertions extensions for ASP.NET Core MVC</AssemblyTitle>
77
<Title>Fluent Assertions for ASP.NET Core MVC</Title>
8-
<VersionPrefix>3.1.0</VersionPrefix>
8+
<VersionPrefix>3.2.0</VersionPrefix>
99
<Authors>Casey Burns;Kevin Kuszyk</Authors>
1010
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
1111
<AssemblyName>FluentAssertions.AspNetCore.Mvc</AssemblyName>

‎src/FluentAssertions.AspNetCore.Mvc/ObjectResultAssertionsBase.cs

+99-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using FluentAssertions.Execution;
1+
using FluentAssertions.Common;
2+
using FluentAssertions.Equivalency;
3+
using FluentAssertions.Execution;
24
using FluentAssertions.Primitives;
35
using Microsoft.AspNetCore.Mvc;
46
using Microsoft.AspNetCore.Mvc.Formatters;
@@ -157,14 +159,108 @@ public TObjectResultAssertion WithDeclaredType(Type expectedDeclaredType, string
157159
var actual = ObjectResultSubject.DeclaredType;
158160

159161
Execute.Assertion
162+
.BecauseOf(reason, reasonArgs)
160163
.ForCondition(expectedDeclaredType == actual)
161164
.WithDefaultIdentifier(Identifier + ".DeclaredType")
162-
.BecauseOf(reason, reasonArgs)
163165
.FailWith(FailureMessages.CommonTypeFailMessage, expectedDeclaredType, actual);
164166

165167
return (TObjectResultAssertion)this;
166168
}
167169

170+
/// <summary>
171+
/// Asserts that the <see cref="ObjectResult.Value"/> is the expected value.
172+
/// </summary>
173+
/// <param name="expectedValue">The expected value.</param>
174+
/// <param name="reason">
175+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
176+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
177+
/// </param>
178+
/// <param name="reasonArgs">
179+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
180+
/// </param>
181+
public TObjectResultAssertion WithValue(object expectedValue, string reason = "", params object[] reasonArgs)
182+
{
183+
object actualValue = ObjectResultSubject.Value;
184+
185+
Execute.Assertion
186+
.BecauseOf(reason, reasonArgs)
187+
.ForCondition(actualValue.IsSameOrEqualTo(expectedValue))
188+
.WithDefaultIdentifier(Identifier + ".Value")
189+
.FailWith(FailureMessages.CommonFailMessage, expectedValue, actualValue);
190+
191+
return (TObjectResultAssertion)this;
192+
}
193+
194+
/// <summary>
195+
/// Asserts that the <see cref="ObjectResult.Value"/> is equivalent to another object.
196+
/// </summary>
197+
/// <param name="expectation">The expected value.</param>
198+
/// <param name="reason">
199+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
200+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
201+
/// </param>
202+
/// <param name="reasonArgs">
203+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
204+
/// </param>
205+
public TObjectResultAssertion WithValueEquivalentTo<TExpectation>(TExpectation expectation,
206+
string reason = "", params object[] reasonArgs)
207+
{
208+
return WithValueEquivalentTo(expectation, config => config, reason, reasonArgs);
209+
}
210+
211+
/// <summary>
212+
/// Asserts that the <see cref="ObjectResult.Value"/> is equivalent to another object.
213+
/// </summary>
214+
/// <param name="expectation">The expected status code.</param>
215+
/// <param name="config">
216+
/// A reference to the <see cref="EquivalencyAssertionOptions{TSubject}"/> configuration object that can be used
217+
/// to influence the way the object graphs are compared. You can also provide an alternative instance of the
218+
/// <see cref="EquivalencyAssertionOptions{TSubject}"/> class. The global defaults are determined by the
219+
/// <see cref="AssertionOptions"/> class.
220+
/// </param>
221+
/// <param name="reason">
222+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
223+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
224+
/// </param>
225+
/// <param name="reasonArgs">
226+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
227+
/// </param>
228+
public TObjectResultAssertion WithValueEquivalentTo<TExpectation>(TExpectation expectation,
229+
Func<EquivalencyAssertionOptions<TExpectation>, EquivalencyAssertionOptions<TExpectation>> config, string reason = "", params object[] reasonArgs)
230+
{
231+
object actualValue = ObjectResultSubject.Value;
232+
233+
actualValue.Should().BeEquivalentTo(expectation, config, reason, reasonArgs);
234+
235+
return (TObjectResultAssertion)this;
236+
}
237+
238+
239+
/// <summary>
240+
/// Asserts that the <see cref="ObjectResult.Value"/> statisfies the <paramref name="predicate"/>.
241+
/// </summary>
242+
/// <param name="predicate">
243+
/// The predicate which must be satisfied by the <see cref="ObjectResult.Value"/>.
244+
/// </param>
245+
/// <param name="reason">
246+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
247+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
248+
/// </param>
249+
/// <param name="reasonArgs">
250+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
251+
/// </param>
252+
public TObjectResultAssertion WithValueMatch<TExpectation>(Expression<Func<TExpectation, bool>> predicate,
253+
string reason = "", params object[] reasonArgs)
254+
{
255+
object actualValue = ValueAs<TExpectation>();
256+
257+
using(var scope = new AssertionScope(Identifier + ".Value"))
258+
{
259+
actualValue.Should().Match(predicate, reason, reasonArgs);
260+
}
261+
262+
return (TObjectResultAssertion)this;
263+
}
168264

169265
/// <summary>
170266
/// Asserts that the <see cref="ObjectResult.StatusCode"/> is the expected status code.
@@ -182,9 +278,9 @@ public TObjectResultAssertion WithStatusCode(int? expectedStatusCode, string rea
182278
var actual = ObjectResultSubject.StatusCode;
183279

184280
Execute.Assertion
281+
.BecauseOf(reason, reasonArgs)
185282
.ForCondition(expectedStatusCode == actual)
186283
.WithDefaultIdentifier(Identifier + ".StatusCode")
187-
.BecauseOf(reason, reasonArgs)
188284
.FailWith(FailureMessages.CommonFailMessage, expectedStatusCode, actual);
189285

190286
return (TObjectResultAssertion)this;

‎tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertionsOfTValue_Tests.cs

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using FluentAssertions.Mvc.Tests.Helpers;
22
using Microsoft.AspNetCore.Mvc;
3-
using Microsoft.AspNetCore.Mvc.Infrastructure;
43
using System;
54
using Xunit;
65

@@ -72,6 +71,28 @@ public void BeConvertibleTo_ShouldBeTheConvertedObject()
7271

7372
actual.Should().BeSameAs(expectation);
7473
}
74+
75+
[Fact]
76+
public void BeObjectResult_GivenActionResultWithObjectResult_ShouldPass()
77+
{
78+
var result = new ActionResult<object>(new object());
79+
80+
result.Should().BeObjectResult(Reason, ReasonArgs);
81+
}
82+
83+
[Fact]
84+
public void BeObjectResult_GivenActionResultWithNotObjectResult_ShouldFail()
85+
{
86+
var result = new ActionResult<object>(new BadRequestObjectResult(new object()));
87+
var failureMessage = FailureMessageHelper.ExpectedContextToBeConvertible(
88+
"result", typeof(ObjectResult).FullName, typeof(BadRequestObjectResult).FullName);
89+
90+
Action action = () => result.Should().BeObjectResult(Reason, ReasonArgs);
91+
92+
action.Should().Throw<Exception>()
93+
.WithMessage(failureMessage);
94+
}
95+
7596
#endregion Public Methods
7697
}
7798
}

‎tests/FluentAssertions.AspNetCore.Mvc.Tests/ObjectResultAssertions_Tests.cs

+81
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ namespace FluentAssertions.AspNetCore.Mvc.Tests
1212
public class ObjectResultAssertions_Tests
1313
{
1414
private const string TestValue = "testValue";
15+
private const string WrongValue = "wrongValue";
16+
17+
private readonly object TestObject = new { Value = "testValue" };
18+
private readonly object GoodObject = new { Value = "testValue" };
19+
private readonly object WrongObject = new { Value = "wrongValue" };
1520
public const string Reason = FailureMessageHelper.Reason;
1621
public readonly static object[] ReasonArgs = FailureMessageHelper.ReasonArgs;
1722

@@ -219,5 +224,81 @@ public void WithStatusCode_GivenUnexpected_ShouldFail()
219224
a.Should().Throw<Exception>()
220225
.WithMessage(failureMessage);
221226
}
227+
228+
[Fact]
229+
public void WithValue_GivenExpected_ShouldPass()
230+
{
231+
var result = new ObjectResult(TestValue);
232+
233+
result.Should().BeObjectResult()
234+
.WithValue(TestValue);
235+
}
236+
237+
[Fact]
238+
public void WithValue_GivenUnexpected_ShouldFail()
239+
{
240+
var result = new ObjectResult(WrongValue);
241+
string failureMessage = FailureMessageHelper.ExpectedContextToBeXButY(
242+
"ObjectResult.Value",
243+
TestValue,
244+
WrongValue);
245+
246+
Action a = () => result.Should().BeObjectResult().WithValue(TestValue, Reason, ReasonArgs);
247+
248+
a.Should().Throw<Exception>()
249+
.WithMessage(failureMessage);
250+
}
251+
252+
[Fact]
253+
public void WithValueEquivalentTo_GivenExpected_ShouldPass()
254+
{
255+
var result = new ObjectResult(TestObject);
256+
257+
result.Should().BeObjectResult()
258+
.WithValueEquivalentTo(GoodObject);
259+
}
260+
261+
[Fact]
262+
public void WithValueEquivalentTo_GivenUnexpected_ShouldFail()
263+
{
264+
var result = new ObjectResult(WrongObject);
265+
string failureMessage = @"Expected member Value to be
266+
""testValue"" with a length of 9 because it is 10, but
267+
""wrongValue"" has a length of 10.
268+
269+
With configuration:
270+
- Use declared types and members
271+
- Compare enums by value
272+
- Match member by name (or throw)
273+
- Without automatic conversion.
274+
- Be strict about the order of items in byte arrays";
275+
276+
Action a = () => result.Should().BeObjectResult().WithValueEquivalentTo(GoodObject, Reason, ReasonArgs);
277+
278+
a.Should().Throw<Exception>()
279+
.WithMessage(failureMessage);
280+
}
281+
282+
[Fact]
283+
public void WithValueMatch_GivenExpected_ShouldPass()
284+
{
285+
var result = new ObjectResult(TestValue);
286+
287+
result.Should().BeObjectResult()
288+
.WithValueMatch<string>(value => value == TestValue);
289+
}
290+
291+
[Fact]
292+
public void WithValueMatch_GivenUnexpected_ShouldFail()
293+
{
294+
var result = new ObjectResult(WrongValue);
295+
string failureMessage = "Expected ObjectResult.Value to match (value == \"testValue\") because it is 10, but found \"wrongValue\".";
296+
297+
Action a = () => result.Should().BeObjectResult().WithValueMatch<string>(value => value == TestValue, Reason, ReasonArgs);
298+
299+
a.Should().Throw<Exception>()
300+
.WithMessage(failureMessage);
301+
}
302+
222303
}
223304
}

0 commit comments

Comments
 (0)
Please sign in to comment.