Skip to content

Commit f8038a8

Browse files
authored
Merge pull request #109 from spencerr/improved-assertion-extensions
Add additional FluentAssertion methods for asserting reasons.
2 parents 5d2af41 + 6fa15e3 commit f8038a8

File tree

4 files changed

+229
-0
lines changed

4 files changed

+229
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using FluentAssertions;
2+
using System;
3+
using Xunit;
4+
using Xunit.Sdk;
5+
6+
namespace FluentResults.Extensions.FluentAssertions.Test.ResultTests
7+
{
8+
public class HaveReasonTests
9+
{
10+
[Theory]
11+
[InlineData("Error 1")]
12+
[InlineData("Error")]
13+
public void A_result_with_expected_reason_throw_no_exception(string expectedError)
14+
{
15+
var failedResult = Result.Fail("Error 1");
16+
17+
Action action = () => failedResult.Should().BeFailure().And.HaveReason(expectedError);
18+
19+
action.Should().NotThrow();
20+
}
21+
22+
[Fact]
23+
public void A_result_without_expected_reason_throw_a_exception()
24+
{
25+
var successResult = Result.Fail("Error 2");
26+
27+
Action action = () => successResult.Should().BeFailure().And.HaveReason("Error 1");
28+
29+
action.Should()
30+
.Throw<XunitException>()
31+
.WithMessage("Expected result to contain reason with message containing \"Error 1\", but found reasons '{Error with Message='Error 2'}'");
32+
}
33+
34+
[Theory]
35+
[InlineData("Error 1")]
36+
[InlineData("Error")]
37+
public void A_result_with_expected_reason_of_type_throw_no_exception(string expectedError)
38+
{
39+
var successResult = Result.Fail(new SomeReason("Error 1"));
40+
41+
Action action = () => successResult.Should().BeFailure().And.HaveReason<SomeReason>(expectedError);
42+
43+
action.Should().NotThrow();
44+
}
45+
46+
[Fact]
47+
public void A_result_without_expected_reason_of_type_throw_a_exception()
48+
{
49+
var successResult = Result.Fail("Error 1");
50+
51+
Action action = () => successResult.Should().BeFailure().And.HaveReason<SomeReason>("Error 1");
52+
53+
action.Should()
54+
.Throw<XunitException>()
55+
.WithMessage("Expected result to contain reason of type \"SomeReason\" with message containing \"Error 1\", but found reasons '{Error with Message='Error 1'}'");
56+
}
57+
58+
[Fact]
59+
public void A_result_with_expected_reason_object_throw_no_exception()
60+
{
61+
var successResult = Result.Fail("Error 1");
62+
63+
Action action = () => successResult.Should().BeFailure().And.HaveReason(new Error("Error 1"));
64+
65+
action.Should().NotThrow();
66+
}
67+
68+
[Fact]
69+
public void A_result_without_expected_reason_object_throw_a_exception()
70+
{
71+
var successResult = Result.Fail("Error 1");
72+
73+
Action action = () => successResult.Should().BeFailure().And.HaveReason(new Error("Error 2"));
74+
75+
action.Should()
76+
.Throw<XunitException>()
77+
.WithMessage("Expected Subject.Reasons {Error with Message='Error 1'} to contain equivalent of Error with Message='Error 2'*");
78+
}
79+
}
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FluentResults.Extensions.FluentAssertions.Test
2+
{
3+
internal class SomeReason : Error
4+
{
5+
public SomeReason(string message) : base(message)
6+
{
7+
8+
}
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using FluentAssertions;
2+
using System;
3+
using Xunit;
4+
using Xunit.Sdk;
5+
6+
namespace FluentResults.Extensions.FluentAssertions.Test.ValueResultTests
7+
{
8+
public class HaveReasonTests
9+
{
10+
[Theory]
11+
[InlineData("Error 1")]
12+
[InlineData("Error")]
13+
public void A_result_with_expected_reason_throw_no_exception(string expectedError)
14+
{
15+
var failedResult = Result.Fail<int>("Error 1");
16+
17+
Action action = () => failedResult.Should().BeFailure().And.HaveReason(expectedError);
18+
19+
action.Should().NotThrow();
20+
}
21+
22+
[Fact]
23+
public void A_result_without_expected_reason_throw_a_exception()
24+
{
25+
var successResult = Result.Fail<int>("Error 2");
26+
27+
Action action = () => successResult.Should().BeFailure().And.HaveReason("Error 1");
28+
29+
action.Should()
30+
.Throw<XunitException>()
31+
.WithMessage("Expected result to contain reason with message containing \"Error 1\", but found reasons '{Error with Message='Error 2'}'");
32+
}
33+
34+
[Theory]
35+
[InlineData("Error 1")]
36+
[InlineData("Error")]
37+
public void A_result_with_expected_reason_of_type_throw_no_exception(string expectedError)
38+
{
39+
var successResult = Result.Fail<int>(new SomeReason("Error 1"));
40+
41+
Action action = () => successResult.Should().BeFailure().And.HaveReason<SomeReason>(expectedError);
42+
43+
action.Should().NotThrow();
44+
}
45+
46+
[Fact]
47+
public void A_result_without_expected_reason_of_type_throw_a_exception()
48+
{
49+
var successResult = Result.Fail<int>("Error 1");
50+
51+
Action action = () => successResult.Should().BeFailure().And.HaveReason<SomeReason>("Error 1");
52+
53+
action.Should()
54+
.Throw<XunitException>()
55+
.WithMessage("Expected result to contain reason of type \"SomeReason\" with message containing \"Error 1\", but found reasons '{Error with Message='Error 1'}'");
56+
}
57+
58+
[Fact]
59+
public void A_result_with_expected_reason_object_throw_no_exception()
60+
{
61+
var successResult = Result.Fail<int>("Error 1");
62+
63+
Action action = () => successResult.Should().BeFailure().And.HaveReason(new Error("Error 1"));
64+
65+
action.Should().NotThrow();
66+
}
67+
68+
[Fact]
69+
public void A_result_without_expected_reason_object_throw_a_exception()
70+
{
71+
var successResult = Result.Fail<int>("Error 1");
72+
73+
Action action = () => successResult.Should().BeFailure().And.HaveReason(new Error("Error 2"));
74+
75+
action.Should()
76+
.Throw<XunitException>()
77+
.WithMessage("Expected Subject.Reasons {Error with Message='Error 1'} to contain equivalent of Error with Message='Error 2'*");
78+
}
79+
}
80+
}

src/FluentResults.Extensions.FluentAssertions/ResultAssertions.cs

+59
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using FluentAssertions;
34
using FluentAssertions.Execution;
45
using FluentAssertions.Primitives;
@@ -42,6 +43,35 @@ public AndWhichConstraint<ResultAssertions, Result> BeSuccess(string because = "
4243
return new AndWhichConstraint<ResultAssertions, Result>(this, Subject);
4344
}
4445

46+
public AndWhichConstraint<ResultAssertions, Result> HaveReason(string message, string because = "", params object[] becauseArgs)
47+
{
48+
Execute.Assertion
49+
.BecauseOf(because, becauseArgs)
50+
.Given(() => Subject.Reasons)
51+
.ForCondition(reasons => reasons.Any(reason => reason.Message.Contains(message)))
52+
.FailWith("Expected result to contain reason with message containing {0}, but found reasons '{1}'", message, Subject.Reasons);
53+
54+
return new AndWhichConstraint<ResultAssertions, Result>(this, Subject);
55+
}
56+
57+
public AndWhichConstraint<ResultAssertions, Result> HaveReason<TReason>(string message, string because = "", params object[] becauseArgs) where TReason : IReason
58+
{
59+
Execute.Assertion
60+
.BecauseOf(because, becauseArgs)
61+
.Given(() => Subject.Reasons.OfType<TReason>())
62+
.ForCondition(reasons => reasons.Any(reason => reason.Message.Contains(message)))
63+
.FailWith("Expected result to contain reason of type {0} with message containing {1}, but found reasons '{2}'", typeof(TReason).Name, message, Subject.Reasons);
64+
65+
return new AndWhichConstraint<ResultAssertions, Result>(this, Subject);
66+
}
67+
68+
public AndWhichConstraint<ResultAssertions, Result> HaveReason(IReason reason, string because = "", params object[] becauseArgs)
69+
{
70+
Subject.Reasons.Should().ContainEquivalentOf(reason, because, becauseArgs);
71+
72+
return new AndWhichConstraint<ResultAssertions, Result>(this, Subject);
73+
}
74+
4575
public AndConstraint<ResultAssertions> Satisfy(Action<Result> action)
4676
{
4777
action(Subject);
@@ -86,6 +116,35 @@ public AndWhichConstraint<ResultAssertions<T>, Result<T>> BeSuccess(string becau
86116
return new AndWhichConstraint<ResultAssertions<T>, Result<T>>(this, Subject);
87117
}
88118

119+
public AndWhichConstraint<ResultAssertions<T>, Result<T>> HaveReason(string message, string because = "", params object[] becauseArgs)
120+
{
121+
Execute.Assertion
122+
.BecauseOf(because, becauseArgs)
123+
.Given(() => Subject.Reasons)
124+
.ForCondition(reasons => reasons.Any(reason => reason.Message.Contains(message)))
125+
.FailWith("Expected result to contain reason with message containing {0}, but found reasons '{1}'", message, Subject.Reasons);
126+
127+
return new AndWhichConstraint<ResultAssertions<T>, Result<T>>(this, Subject);
128+
}
129+
130+
public AndWhichConstraint<ResultAssertions<T>, Result<T>> HaveReason<TReason>(string message, string because = "", params object[] becauseArgs) where TReason : IReason
131+
{
132+
Execute.Assertion
133+
.BecauseOf(because, becauseArgs)
134+
.Given(() => Subject.Reasons.OfType<TReason>())
135+
.ForCondition(reasons => reasons.Any(reason => reason.Message.Contains(message)))
136+
.FailWith("Expected result to contain reason of type {0} with message containing {1}, but found reasons '{2}'", typeof(TReason).Name, message, Subject.Reasons);
137+
138+
return new AndWhichConstraint<ResultAssertions<T>, Result<T>>(this, Subject);
139+
}
140+
141+
public AndWhichConstraint<ResultAssertions<T>, Result<T>> HaveReason(IReason reason, string because = "", params object[] becauseArgs)
142+
{
143+
Subject.Reasons.Should().ContainEquivalentOf(reason, because, becauseArgs);
144+
145+
return new AndWhichConstraint<ResultAssertions<T>, Result<T>>(this, Subject);
146+
}
147+
89148
public AndConstraint<ResultAssertions<T>> HaveValue(T expectedValue, string because = "", params object[] becauseArgs)
90149
{
91150
Execute.Assertion

0 commit comments

Comments
 (0)