When I Create an instance of Mock with MockBehavior.Strict I'm getting the error
An exception of type 'Moq.MockException' occurred in Moq.dll but was not handled in user code
Additional information: DbContext.Set() invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
But I already made the setup for every table including that one:
var mockContext = new Mock<JournalsDB>(MockBehavior.Strict);
mockContext.Setup(m => m.Publications).Returns(mockPublicationSet.Object);
mockContext.Setup(m => m.Journals).Returns(mockJournalSet.Object);
mockContext.Setup(m => m.AspNetUsers).Returns(mockUserSet.Object);
mockContext.Setup(m => m.AspNetRoles).Returns(mockRoleSet.Object);
mockContext.Setup(m => m.AspNetUserClaims).Returns(mockClaimSet.Object);
mockContext.Setup(m => m.AspNetUserLogins).Returns(mockLoginSet.Object);
I suspect that the issue maybe is with my Repository Implementation or the DbContext Implementation:
public class JournalRepository<DataObject, DataContext> : IRepository<DataObject, DataContext>, IDisposable
where DataObject : class
where DataContext : DbContext
{
#region Propiedades
private readonly DataContext _ctx;
etc...
public partial class JournalsDB : DbContext
{
public JournalsDB()
: base("name=JournalsDB")
{
}
public JournalsDB(string connectionName)
: base(connectionName)
{
}
etc...
EDIT:
Without MockBehaviour.Strict I get the error Value cannot be null. Parameter name: source when querying any DbSet but the DbSets are correctly populated.
I really think you're taking the wrong approach here, to be honest. Mocking DbContext is really painful, because that's a really wide interface. This is really a case of trying to dummy up an interface that you don't own. Mocking someone else's interface is always an invitation for trouble. In the case of DbContext you would really want to also mock the behavior of calls like SaveChanges().
I would isolate the usage of DbContext behind a much smaller interface that is easier to mock. Then, you'll have two types of tests you want to write:
Unit test whatever uses the new interface. Those tests will be easier to write because you won't have to dummy up the DbContext
Test the class that implements the interface using a real database with real data in it. This way, you can test your data access layer in isolation.
For a more detailed explanation, see the answer I wrote here: Effort- FirstOrDefault returns null when Faking Database
Related
I'm trying to inject TenantProvider into DbContext
public class AppDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
{
public int? _tenantId;
public ITenantProvider _tenantProvider;
public AppDbContext(
DbContextOptions<AppDbContext> options,
ITenantProvider tenantProvider
)
: base(options)
{
_tenantProvider = tenantProvider;
}
but I don't understand how to register it correctly - if I put the breakpoint in the constructor - tenantProvider is null.
The bit from Startup.cs
services.AddDbContext<AppDbContext>(options => AppDbContextOptionsBuilder.Get());
the next line is required to inject the DbContext into a controller or a service (if I add ServiceLifetime.Scoped as a second parameter to the method above - AddDbContext - the feature doesn't work):
services.AddScoped(p => new AppDbContext(AppDbContextOptionsBuilder.Get(), p.GetService<ITenantProvider>()));
(Entity Framework is a separate project in my solution)
When using .AddScoped method - we can pass TenantProvider into constructor by resolving it using .GetService method.
Does anyone have an idea of how to resolve TenantProvider in .AddDbContext method?
Additional info:
I was trying to replace ITenantProvider in the constructor of DbContext with IHttpContextAccessor - the latter is registered as singleton. But the acessor parameter is still null.
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
I don’t really understand what your AddScoped call is supposed to do. AddDbContext will already register the database context properly with the service collection. So when you resolve the context through dependency injection, additional dependencies will be automatically resolved.
So it should be enough to do this:
services.AddDbContext<AppDbContext>(options => …);
services.AddSingleton<ITenantProvider, TenantProvider>();
And then, you can depend on your AppDbContext using constructor injection, e.g. in your controllers.
Two notes though:
When configuring options, you should modify the passed options object. So you should not just return AppDbContextOptionsBuilder.Get() but instead use the passed options object and edit that.
You should really think about whether your database context having a dependency on your tenant provider is the right thing to do. As per SRP, your database should only do a single thing and that is provide database access.
Depending on how your tenant provider affects your database access, it might make more sense to move this dependency up one level into some service that uses both the database context and the tenant provider to query data in the right way.
I am building web APIs in ASP.NET Core 1.1.
I have a number different databases (for different systems) which have common base schemas for configuration items such as Configuration, Users and groups (about 25 tables in all). I am trying to avoid duplicating the quite extensive EF configuration for the shared part of the model by inheriting from a base class as shown in the diagram.
However, this does not work because of the Entity Framework (EF) requirement to pass DbContextOptions<DerivedRepository> as a parameter to the constructor, where DerivedRepository must match the type of the repository the constructor is called on. The parameter must then be passed down to the base DbContext by calling :base(param).
So when (for example) InvestContext is initialised with DbContextOptions<InvestContext>, it calls base(DbContextOptions<InvestContext>) and EF throws an error because the call to the ConfigurationContext constructor is receiving a parameter of type DbContextOptions<InvestContext> instead of the required type DbContextOptions<ConfigurationContext>. Since the options field on DbContext is defined as
private readonly DbContextOptions _options;
I can't see a way around this.
What is the best way to define the shared model once and use it multiple times? I guess I could create a helper function and call it from every derived context, but it's not nearly as clean or transparent as inheritance.
I would like to bring this post from the OP's GitHub issue to everyone's attention:
I was able to resolve this without a hack by providing a protected constructor that uses DbContextOptions without any type. Making the second constructor protected ensures that it will not get used by DI.
public class MainDbContext : DbContext {
public MainDbContext(DbContextOptions<MainDbContext> options)
: base(options) {
}
protected MainDbContext(DbContextOptions options)
: base(options) {
}
}
public class SubDbContext : MainDbContext {
public SubDbContext (DbContextOptions<SubDbContext> options)
: base(options) {
}
}
OK, I have got this working in a way which still uses the inheritance hierarchy, like this (using InvestContext from above as the example):
As stated, the InvestContext class receives a constructor parameter of type DbContextOptions<InvestContext>, but must pass DbContextOptions<ConfigurationContext> to it's base.
I have written a method which digs the connectionstring out of a DbContextOptions variable, and builds a DbContextOptions instance of the required type. InvestContext uses this method to convert its options parameter to the right type before calling base().
The conversion method looks like this:
protected static DbContextOptions<T> ChangeOptionsType<T>(DbContextOptions options) where T:DbContext
{
var sqlExt = options.Extensions.FirstOrDefault(e => e is SqlServerOptionsExtension);
if (sqlExt == null)
throw (new Exception("Failed to retrieve SQL connection string for base Context"));
return new DbContextOptionsBuilder<T>()
.UseSqlServer(((SqlServerOptionsExtension)sqlExt).ConnectionString)
.Options;
}
and the InvestContext constructor call changes from this:
public InvestContext(DbContextOptions<InvestContext> options):base(options)
to this:
public InvestContext(DbContextOptions<InvestContext> options):base(ChangeOptionsType<ConfigurationContext>(options))
So far both InvestContext and ConfigurationContext work for simple queries, but it seems like a bit of a hack and possibly not something the designers of EF7 had in mind.
I am still concerned that EF is going to get itself in a knot when I try complex queries, updates etc. It appears that this is not a problem, see below)
Edit: I've logged this problem as an issue with the EF7 team here, and a team member has suggested a change to the EF Core core as follows:
"We should update the check to allow TContext to be a type that is derived from the current context type"
This would solve the problem.
After further interaction with that team member (which you can see on the issue) and some digging through the EF Core code, the approach I've outlined above looks safe and the best approach until the suggested change is implemented.
Depending on your requirements you can simply use the non type specific version of DbContextOptions.
Change these:
public ConfigurationContext(DbContextOptions<ConfigurationContext> options):base(options)
public InvestContext(DbContextOptions<InvestContext> options):base(options)
to this:
public ConfigurationContext(DbContextOptions options):base(options)
public InvestContext(DbContextOptions options):base(options)
Then if you create your ConfigurationContext first, the classes that inherit it seem to get the same configuration. It may also depend on the order in which you initialize the different contexts.
Edit:
My working example:
public class QueryContext : DbContext
{
public QueryContext(DbContextOptions options): base(options)
{
}
}
public class CommandContext : QueryContext
{
public CommandContext(DbContextOptions options): base(options)
{
}
}
And in Startup.cs
services.AddDbContext<CommandContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<QueryContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
alternatively, in a test class:
var connectionString = "Data Source=MyDatabase;Initial Catalog=MyData;Integrated Security=SSPI;";
var serviceProvider = new ServiceCollection()
.AddDbContext<QueryContext>(options => options.UseSqlServer(connectionString))
.BuildServiceProvider();
_db = serviceProvider.GetService<QueryContext>();
I've been looking at various approaches to implementing the repository pattern with EF, specifically using a generic repository.
I had been trying to use an IRepository that would have an IContext property, so that the only difference between any implementation of the IRepository would be the context. I've found this difficult enough that I've abandoned the "fake context" approach, and now just have a dictionary of List as my "context" in the fake repository:
public Dictionary<Type, object> _sets = new Dictionary<Type, object>();
And to manipulate it, would do something like this in the fake:
public void Add<T>(T entity) where T : class
{
var set = _sets[typeof (T)] as IQueryable<T>;
var updatedSet = set.ToList();
updatedSet.Add(entity);
_sets[typeof (T)] = updatedSet.AsQueryable<T>();
}
In the real repository, I can just use:
void Add<T>(T entity)
{
Set<T>().Add(entity);
}
In my Update method, I would have to have similarly different implementations to accomodate a real context inheriting DbContext, and a fake using a collection-based approach.
This approach is making me nervous. As others have mentioned in other questions, now my repository implementations are so different, that I don't feel I can trust a test until it's been run with both a fake and real repository.
Am I just a noob that is overthinking this? Or is there a better way to implement a fake context that behaves more like a DbContext so I don't have to have such drastically different classes implementing the repository interface?
To summarize: I understand the advantages of testing with an in-memory repository. My question is, when I have to make two implementations of the repository that are this different, does that mean that I am doing something wrong, or is this just the cost of testing with fakes, and if the logic tests pass, I shouldn't sweat it so much?
Here's what we did in the project I'm working on: We have a repository wrapper class around EF so that way we can use mocks in the unit testing when it's needed. I considered doing an in memory repository like you're doing, but I ended up deciding against it because I only really needed it for doing querying. However, since Linq To Entities is a subset of Linq to Objects. A unit test might pass, but then fail the integration test since you might have been using functionality not part of Linq to Entities. If I need to integration test that query and couldn't trust the unit test, it didn't feel like it made sense to do both.
For unit testing, I just had a mock of the repository and verified that the appropriate method (Insert or whatever) had been called. For integration testing for deleting/insert/whatever, just hit the actual database.
For the actual querying, I just did integration testing. I moved the query to a separate function. My code would call that function to retrieve the query results and I could just integration test the function with the query in it separately and unit test the processing of the query results.
I don't know if that made sense or if there's a better way to do it, but that's what I ended up doing.
Alternatively, if you want to continue with the in-memory implementation
I think you should be able to do the following:
Just have a list of objects and use the OfType to return the correct type:
public TEntity Get<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> where, params System.Linq.Expressions.Expression<Func<TEntity, object>>[] includeProperties) where TEntity : class
{
return _repositories.OfType<TEntity>().AsQueryable().Where(where).FirstOrDefault();
}
public TEntity Insert<TEntity>(TEntity tEntity) where TEntity : class
{
_repositories.Add(tEntity);
return tEntity;
}
I've run into a bit of a problem with EF looking for the best practice for this problem:
public void TestEntityFramework_UOWImplementation()
{
using (UnitOfWorkInventory uow = new UnitOfWorkInventory())
{
IMaterialRepository repos = new MaterialRepository(uow);
Material mat = GetMaterial("Mikes Material", 1);
mat.CostPrice = 20;
repos.InsertOrUpdate(mat);
uow.Commit();
}
}
private Material GetMaterial(string sku, int clientId)
{
IMaterialRepository repos = new MaterialRepository(new UnitOfWorkInventory();
return repos.Find(sku, clientId);
}
In the TestEntityFramework_UOWImplementation() method, its fine, i call create a scope for my unit of work.. and create a repository inside it.
But when i want to getMaterials() as below.. I have no access to the unit of work or the repository, unless i actually pass it as a parameter! This is clearly not particularly nice.
How do people get around this problem??
Thanks in advance!
Neil
In your implementation you wont have access to the Unit of Work like that. What I do is use an IoC container and Dependency Injection to handle it. I have a WCF service that uses Unit of Work with a repository pattern against EF5.
You can read more about repository pattern, unit of work, and EF here but basically what I do is in the constructor of my service class I inject the Unit of Work like so:
private readonly IUnitOfWork uow;
public LoanService(IUnitOfWork unitOfWork)
{
uow = unitOfWork;
}
Then I can use uow.WhateverMethod in my repos anywhere in the service. I use Ninject to handle the injection of IUnitOfWork. Hope it helps you.
If anyone was looking for a way around this, I done something a bit different.
I used a Dependency Injection framework (StructureMap) to handle all DI, so everytime i instantiate a repository it will retrieve the DBContext from the Service Locator of StructureMap. I also make the dbcontext scope to be for the duration of the request from the webserver.
The advantage here being that everytime i retrieve or inject a DBContext, it will retrieve the same context for the duration of the request meaning i can use this across multiple methods and class! I pass the interface type as a generic param to the constructor, meaning that i can point the repo as different contexts. Helpful in applications where there are lots of dbcontexts.
Repo Constructor Eg:
public class PurchaseOrderRepository<TDbContext> : GenericRepository<PurchaseOrder>, IPurchaseOrderRepository<TDbContext> where TDbContext : DbContext
{
public PurchaseOrderRepository()
: base((TDbContext)ObjectFactory.GetInstance<TDbContext>())
{
}
}
Usage:
//resolves the request scope InventoryContext...
var pRepos = new PurchaseOrderRepository<IInventoryContext>();
and the structure map dependency looks like:
For<IInventoryContext>().HttpContextScoped().Use<InventoryContext>();
Let me say, I have come to the conclusion (after a lot of trial) that Repository & Unit of Work when using Entity Framework is just wrong, wrong, wrong and this says why quite well.
But I really hate on those embedded queries. Question is, where can I put them instead if I'm so against a repository, etc? (clean answers only please, examples much appreciated).
I just nuked two projects containing my repositories, unit of work and interfaces with hundreds of files because the payback was nowhere to be seen. I think lots of people, myself included, just jumped on the Repository bandwagon because that's what everybody else was doing but in retrospect, I think it's really a ride to nowhere.
/sigh
Richard
Where do you expect to put them? You have only few choices:
Let them be where they are and use custom extension methods, query views, mapped database views or custom defining queries to define reusable parts
Expose every single query as method on some separate class. The method mustn't expose IQueryable and mustn't accept Expression as parameter = whole query logic must be wrapped in the method. But this will make your class covering related methods much like repository (the only one which can be mocked or faked). This implementation is close to implementation used with stored procedures.
You will do the same as in previous method but instead of placing queries in separate class you will put them as static methods to entity directly. This is much worse testable because static methods cannot be replaced by mocking (it requires more complex testing framework). This is part of active record pattern where each entity is responsible for its loading and saving to database.
Example of custom extension method:
public static IQueryable<TEntity> GetByName(this IQueryalbe<TEntity> query, string name)
where TEntity : IEntityWithName
{
return query.Where(e => e.Name == name);
}
Example of custom class exposing methods:
public class QueryProvider
{
public QueryProvider() {}
public IEnumerable<TEntity> GetByName(IYourContext context, string name)
where TEntity : IEntityWithName
{
return context.CreateObjectSet<TEntity>().Where(e => e.Name == name).ToList();
}
}
Build Reusable, Testable Queries Part 1
This is a blog post I wrote about building reusable queries. Using Extension Methods allows you to build composable queries.
using a pattern like the specification pattern can help you build queries that can be reused or saved (serialized). Further more if you have a double entry system you can execute the same query instance over two different databases.
the following example does not use EF but replace the IEnumerable by an EF context and you get what ou are looking for. parameters are passed in through the constructor.
public class PartialMatchQuery : IModelQuery<string, IEnumerable<string>>
{
private readonly string partial;
public PartialMatchQuery(string partialString)
{
partial = partialString;
}
public IEnumerable<string> Execute(IEnumerable<string> model)
{
return model.Where(s => s.ToLower().Contains(partial));
}
}