FakeItEasy: Describing a call fails when the ToString() of an argument throws an exception

Say we setup a strict fake:

var a = A.Fake<SomeInterface>(s=>s.Strict()); //A strict fake!
var b = A.Fake<SomeOtherInterface>(); //strictness does not matter...

and then we verify the strict fake was passed as an argument to another mock:

//a.ToString() is called for some reason, however a is a strict fake
A.CallTo(()=>b.SomeMethod(a)).MustHaveHappened()

FakeItEasy throws an Exception:

FakeItEasy.ExpectationException : Call to non configured method "ToString" of strict fake.

Call Stack:

   at FakeItEasy.FakeOptionsBuilderExtensions.<Strict>b__0<T>(IFakeObjectCall call)
   at FakeItEasy.Configuration.BuildableCallRule.Apply(IInterceptedFakeObjectCall fakeObjectCall)
   at FakeItEasy.Core.FakeManager.FakeItEasy.Core.IFakeCallProcessor.Process(IWritableFakeObjectCall fakeObjectCall)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.ObjectProxy_4.ToString()
   at FakeItEasy.Expressions.ArgumentConstraints.EqualityArgumentConstraint.WriteDescription(IOutputWriter writer)
   at FakeItEasy.Expressions.ExpressionCallMatcher.AppendArgumentsListString(StringBuilder result)
   at FakeItEasy.Expressions.ExpressionCallMatcher.ToString()
   at FakeItEasy.Configuration.BuildableCallRule.WriteDescriptionOfValidCall(IOutputWriter writer)
   at FakeItEasy.Configuration.RuleBuilder.MustHaveHappened(Repeated repeatConstraint)

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 67 (59 by maintainers)

Most upvoted comments

I suggest we release a very simple change now which catches the exception, falling back to the type name. That will solve the general case when the ToString() of any object throws an exception, including this specific bug. After that, #984 may still have value, but we can pursue it for it’s own merits independently of fixing this bug.

That makes sense.

As mentioned in your PR, I think we should prefix the type name with “Faked” if the value is a fake, since this is the default ToString() behavior for fakes.

Even if we do some trickery around strictness and System.Object methods, is there still a fundamental flaw here that we need to fix regardless? I.e. we call ToString() on objects when generating messages about them, and we don’t catch exceptions on that call. Perhaps the object itself has a badly behaved ToString method, but we still want to generate the message, rather than have an unhandled exception.

IMO we shouldn’t call ToString() at all on a fake, whether it’s strict or not. In my solution we call IFakeObject.ToString() instead. For non-fakes, I agree that we should catch the exception.