0

I have encountered an issue that is related with mocking sut object's own method like following.

AutoFake FakeResolver = new AutoFake();
ProductQueryService _sut = FakeResolver.Resolve<ProductQueryService>();
// stubing another virtual method in the testing object itself
A.CallTo(() => _sut.GetLookupCache()).Returns(Task.FromResult(fakeData)); // throws ArgumentException:The specified object is not recognized as a fake object

//method under test is GetBrands
List<BrandDto> brands = await _sut.GetBrands();

Is there any suggestion about this?

1 Answers1

0

I think the problem is that Autofac.Extras.FakeItEasy doesn't fake concrete types, instead falling back to the default container behaviour of creating an actual instance of the requested type. I'm not an Autofac expert, but here's my reasoning:

In the docs, we see

… package allows you to automatically create fake dependencies for both concrete and fake abstract instances in unit tests using an Autofac container

The wording is a little ambiguous, but I think it's saying that concrete dependencies will be provided and abstract instances will be faked.

I then took a peek at the implementation and found in FakeRegistrationHandler this:

if (typedService == null ||
    (!typedService.ServiceType.GetTypeInfo().IsInterface && !typedService.ServiceType.GetTypeInfo().IsAbstract) ||
    (typedService.ServiceType.GetTypeInfo().IsGenericType && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) ||
    typedService.ServiceType.IsArray ||
    typeof(IStartable).IsAssignableFrom(typedService.ServiceType))

This is the check to see if the extension will fake the requested service type. A concrete ProductQueryService isn't an interface or abstract, so I think the container will do nothing.

I don't see an easy way to instruct the extension to fake all concrete types, but I'm sure you could add a one-off registration for any concrete type (or set of types - maybe everything in your namespace) that you like.

I was about to suggest raising an issue on Autofac, but I see you've done so. I wish I'd looked there first.


I'll also caution that in general, faking the System Under Test is not my first choice of testing techniques. If possible, I would extract a dependency that can be injected into your SUT. Then fake it. If represented as an interface or abstract class, you could easily use Autofac.Extras.FakeItEasy to provide it.

In the meantime, I'm going to make some notes over at Autofac.Extras.FakeItEasy issue 14.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111