0

I'm using Entity Framework 6 and want to unit test some of my business logic code. Following Microsoft's example on how to do this, they provide the following example using MOQ:

var mockSet = new Mock<DbSet<Blog>>(); 

var mockContext = new Mock<BloggingContext>(); 
mockContext.Setup(m => m.Blogs).Returns(mockSet.Object); 

var service = new BlogService(mockContext.Object); 

I'm using FakeItEasy instead of MOQ, and I'd hoped it would be just as simple, however FakeItEasy complains that it can't create a fake of my DbSet using the following:

var fakeDbSet = A.Fake<DbSet<InstalledProduct>>();

I get an exception as follows:

FakeItEasy.Core.FakeCreationException: Failed to create fake of type "TN.Prs.Persistence.LicenseContext".

Below is a list of reasons for failure per attempted constructor: No constructor arguments failed: No usable default constructor was found on the type TN.Prs.Persistence.LicenseContext. An exception was caught during this call. Its message was: Access is denied: 'TN.Prs.Persistence.LicenseContext'.

at FakeItEasy.Core.DefaultExceptionThrower.ThrowFailedToGenerateProxyWithResolvedConstructors(Type typeOfFake, String reasonForFailureOfUnspecifiedConstructor, IEnumerable1 resolvedConstructors) at FakeItEasy.Creation.FakeObjectCreator.TryCreateFakeWithDummyArgumentsForConstructor(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, String failReasonForDefaultConstructor, Boolean throwOnFailure) at FakeItEasy.Creation.FakeObjectCreator.CreateFake(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, Boolean throwOnFailure) at FakeItEasy.Creation.DefaultFakeAndDummyManager.CreateFake(Type typeOfFake, FakeOptions options) at FakeItEasy.Creation.DefaultFakeCreatorFacade.CreateFake[T](Action1 options) at FakeItEasy.A.FakeT at TN.Prs.RegistrationServices.Specifications.when_activating_a_product_from_a_valid_digitally_signed_activation_key.<.ctor>b__0() in

My POCO classes are internal rather than public, but I've added the InternalsVisibleTo attributes as appropriate, for DynamicProxyGenAssembly2. When I make the classes public, everything works, but I really don't want to expose these classes publicly. I would appreciate any suggestions.

Here is my context class:

internal class LicenseContext : DbContext
{
    public LicenseContext()
    {

    }
    public virtual DbSet<InstalledProduct> ManagedProducts { get; set; }
}
Yuliam Chandra
  • 14,494
  • 12
  • 52
  • 67
Tim Long
  • 13,508
  • 19
  • 79
  • 147
  • I fail to see how this has anything to do with Entity Framework. It's entirely a problem with FakeItEasy and using internal classes, it would be a problem with any other internal objects you wanted to fake. – Erik Funkenbusch Jul 27 '14 at 20:58
  • @Yuliam I appreciate the sentiment but please don't mess with my indentation (we have always used whitesmiths style). You may think your preference is an improvement but it's a bit arrogant of you to just assume that it's OK to override my preference. – Tim Long Jul 27 '14 at 20:58
  • @ErikFunkenbusch If you are referring to the EntityFramework tag, then I included that because I felt this is a situation that other entity framework users may have run into, and others may encounter in the future. I agree with you though that the problem isn't directly with entity framework. – Tim Long Jul 27 '14 at 21:01
  • Well, your question title specifically calls out `DbSet`, so it makes it seem like an EF specific problem. In any event, is your assembly strongly named? And you added `InternalsVisibleTo` to your assembly that contains your internal classes, right? Not your Test assembly? – Erik Funkenbusch Jul 27 '14 at 21:02
  • @ErikFunkenbusch Well, yes, I mentioned DbSet because that's what was giving me the problem and Microsoft says it should work. Again I agree with you, definitely not an EF problem, it was always going to be a problem with my code, but I like to give as much context (pardon the pun) as possible because I doubt I will be the only person every to run into this when trying to mock a DbSet and you never know what is going to be important until you have the solution (which I do now have, by the way). – Tim Long Jul 27 '14 at 21:09

1 Answers1

1

Problem solved!

Before I added the InternalsVisibleTo attributes, FakeItEasy complained and told me to add those attributes and I was delighted to see that it gave me the exact code I needed right in the error message. I even remarked to one of my colleagues, "now THAT is what I call an error message!". The attribute it suggested was:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

Unfortunately that doesn't work and I get an 'Access Denied' error. It might be that the public key isn't correct, but since my assemblies are not strong-named, I simply removed the public key from the attributes and everything works.

Eventually I will have to strong-name my assemblies so I will have to solve this public key problem eventually, but I know what to do so it shouldn't be an obstacle.

Tim Long
  • 13,508
  • 19
  • 79
  • 147
  • I'm surprised/sad that you were provided with a bad error message. We're supposed to be detecting whether we need to include the public key in the error message since [Issue 157](https://github.com/FakeItEasy/FakeItEasy/issues/157) was fixed in release 1.14. I may have missed a case, but before I start ripping the world apart, could you confirm what version of FakeItEasy you're using? Thanks. – Blair Conrad Jul 28 '14 at 13:08