如何通过包装器模拟上下文

时间:2016-12-06 07:43:24

标签: c# unit-testing mocking wrapper dbcontext

我有一种情况,我通过包装器使用上下文。包装器用于服务层。问题是如何在这种情况下模拟上下文?

上下文

public class DbContext : System.Data.Entity.DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        ...

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Report> Reports { get; set; }
}

包装

public interface IDbContextWrapper<out TContext> where TContext : System.Data.Entity.DbContext, new()
{
    T Call<T>(Func<TContext, T> func);

    void Call(Action<TContext> action);
}

包装器实施

public class DbContextWrapper<TContext> : IDbContextWrapper<TContext> where TContext : System.Data.Entity.DbContext, new()
{

    public virtual TContext BuildContext(bool enableChangeTracking = true, bool enableLazyLoading = false, bool enableProxyCreation = false)
    {
        var result = new TContext();
        result.Configuration.AutoDetectChangesEnabled = enableChangeTracking;
        result.Configuration.LazyLoadingEnabled = enableLazyLoading;
        result.Configuration.ProxyCreationEnabled = enableProxyCreation;
        return result;
    }

    public virtual T Call<T>(Func<TContext, T> func)
    {
        using (var context = BuildContext())
        {
            return func(context);
        }
    }

    public virtual void Call(Action<TContext> action)
    {
        using (var context = BuildContext())
        {
            action(context);
        }
    }
}

我需要使用Mocks进行单元测试的服务及其方法

public class ReportService : IReportService
{
    private readonly IDbContextWrapper<DbContext> _contextWrapper;

    public ReportService(IDbContextWrapper<DbContext> contextWrapper)
    {
        _contextWrapper = contextWrapper;
    }


    public Report GetPreviousReport(int currentReportId, int lineId)
    {
        return _contextWrapper.Call(
            context => context.Reports
                .Where(item => item.Id < currentReportId && item.LineId == lineId)
                .OrderBy(item => item.Id)
                .First());
    }

    public Report GetNextReport(int currentReportId, int lineId)
    {
        return _contextWrapper.Call(
            context => context.Reports
                .Where(item => item.Id > currentReportId && item.LineId == lineId)
                .OrderBy(item => item.Id)
                .First());
    }
}

1 个答案:

答案 0 :(得分:1)

在测试中,您可以创建StubTContext并初始化Reports以返回测试数据。然后使用IDbContextWrapper初始化您正在测试的系统ReportService。

在准备之后使用Moq来模拟IDbContextWrapper,如下所示:

Mock<IDbContextWrapper<StubTContext>> mock = new Mock<IDbContextWrapper<StubTContext>>();

mock.Setup(m => m.Call(It.IsAny<Action<StubTContext>>())).Callback<Action<StubTContext>>(a => a.Invoke(new StubTContext()));

您还可以通过构造函数实现StubTContext来提供测试数据,然后在模型中将测试数据传递给它。像这样:

public StubTContext : DbContext
{
   public StubTContex(DbSet<Report> reports)
   {
       Reports = reports;
   }
}

然后在模拟

mock.Setup(m => m.Call(It.IsAny<Action<StubTContex>>())).Callback<Action<StubTContex>>(a => a.Invoke(new StubTContex(*YOUR REPORTS*)));