-
Notifications
You must be signed in to change notification settings - Fork 179
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
Provide better feedback when call matcher throws #1341
Comments
Thanks for writing, @Mertsch. I can see how an exception being thrown in the matcher is really causing some pain. I feel for you. In the meantime, note that you can get better results in the face of some failures by providing an argument value formatter for If you include a class like this: public class JObjectFormatter : ArgumentValueFormatter<JObject>
{
protected override string GetStringValue(JObject argumentValue)
{
return argumentValue.ToString();
}
} anywhere in your test project, you'll see output like this:
instead of
|
If a call matcher throws, it's still appropriate for the assertion to fail (not just not match, but fail with an exception), but it should clearly indicate that the matcher threw (describing it as well as possible) and it should still indicate which calls have been made to the Fake. |
@blairconrad Thanks for the Tip, nice to know that
|
Sorry @Mertsch, which "User provided detail" message is this? I'm a little slow today. |
@blairconrad Hehe 😀 I mean the things that you write into the Thank you for your activeness in this project, that is so nice to see as a developer myself 😃 |
Oh, yes. I see! For sure, if we're spewing a description of the failed matcher, we should use the user's description. Very good point. |
So, there are two different issues here:
|
@thomaslevesque Yes, even though I took the JObject just as an example, in my specific production code case, it was a different object containing a JObject and the displayed info was the usual object.ToSting() which wasn't to helpful either, as that was just the class name. But before that it's important to know where the error was 😀 |
Well, it's what custom formatters are for 😉 |
@thomaslevesque Just tried a formatter, works great 😄 |
I'm wondering what exception we should throw when a user-provided delegate throws. None of the existing exceptions in FIE is a good fit, so we should probably introduce a new one. Also, there are plenty of other places where we invoke user-provided delegates. We should probably improve these too. |
I think a new exception makes sense. As you say, there are lots of places we could run into this problem. Even in this one situation, the matcher may fail, the repetition count may fail, the description of the matcher may fail, and the description of an argument value may fail. And I'm probably missing some! |
Yeah, lots of different situations. What about |
For discussion, here's a spec that documents the desired behavior: public class UserCallbackExceptionSpecs
{
public interface IFoo
{
int Bar(int x);
}
[Scenario]
public void ExceptionInArgumentMatcher(IFoo fake, Exception exception)
{
"Given a fake"
.x(() => fake = A.Fake<IFoo>());
"And a call to the fake is configured with a custom argument matcher that throws an exception"
.x(() => A.CallTo(() => fake.Bar(A<int>.That.Matches(i => ThrowException()))).Returns(42));
"When the configured method is called"
.x(() => exception = Record.Exception(() => fake.Bar(0)));
"Then a UserCallbackException should be thrown"
.x(() => exception.Should().BeAnExceptionOfType<UserCallbackException>());
"And its message should describe where the exception was thrown from"
.x(() => exception.Message.Should().Be("Argument matcher '<i => ThrowException()>' threw an exception. See inner exception for details."));
"And the inner exception should be the original exception"
.x(() => exception.InnerException.Should().BeAnExceptionOfType<MyException>().Which.Message.Should().Be("Oops"));
}
private static bool ThrowException()
{
throw new MyException("Oops");
}
public class MyException : Exception
{
public MyException(string message, Exception inner = null)
: base(message, inner)
{
}
}
} |
Thank you very much @blairconrad and @thomaslevesque . You are awesome. |
This change has been released as part of FakeItEasy 4.7.0. Thanks, @Mertsch. Look for your name in the release notes! 🥇 |
Please consider the following code and comments on it. As you can see in the examples, an exception in rule building makes finding the issue very hard, since you have no debug info at all, that is usually very rich with FIE
The text was updated successfully, but these errors were encountered: