ASP.NET在本地方法中测试DbContext

时间:2015-08-20 05:28:27

标签: c# asp.net-mvc integration-testing

我有一个ASP.NET MVC项目,我正在编写我的服务:

public class UserService : IUserService
{
    public void AddUser(UserModel userModel)
    {
        if (ModelState.IsValid){
            var user = new User
            {
                FirstName = userModel.FirstName,
                LastName = userModel.LastName,
                Email = userModel.Email,
                Age = userModel.Age
            };
            using (var context = new MyDbContext())
            {
                context.Users.Add(user);
            }
        }
    }
    //... More code for service
}

我的DbContext课程:

public class MyDbContext : DbContext 
{
    public MyDbContext(): base("name=mydb"){}

    public DbSet<User> Users {get; set;}

    //.. More domain objects.
}

这在大多数情况下运行正常,但是当我想尝试测试它时会出现问题。我遵循一般指导原则here并嘲笑它,但这只是在DbContext被声明为类实例而不是函数变量的情况下。我想这样做,因为它使我能够控制事务和上下文处理。有人对如何做到这一点有任何建议吗?

我的嘲笑是这样的:

public class UserServiceTest 
{
    [Fact]
    public void TestAddUser()
    {
        var userSet = GetQueryableMockDbSet(userData.ToArray());
        var context = new MyDbContext
        {
            Users = userSet
        };
        var userService = new UserService();
        userService.AddUser(); // HOW DO I GET CONTEXT IN HERE?
    }   

    private static DbSet<T> GetQueryableMockDbSet<T>(params T[] sourceList) where T : class
        {
            var queryable = sourceList.AsQueryable();

            var dbSet = new Mock<DbSet<T>>();
            dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
            dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
            dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());

            return dbSet.Object;
        }
}

3 个答案:

答案 0 :(得分:2)

实现

目标的一种方法
  

我想这样做,因为它使我能够控制交易和上下文处理。

将按照

的方式做点什么
public class UserService : IUserService {
   private ContextFactory _ContextFactory;

   public UserService(ContextFactory contextFactory) {
       _ContextFactory = contextFactory;
   }

   public void AddUser(UserModel userModel) {
       ...
       using (var context = _ContextFactory.CreateInstance()) {
           context.Users.Add(user);
       }
   }

}

这将允许您注入ContextFactory的不同实例,这些实例将使用模拟创建DbContext

答案 1 :(得分:1)

我绝对会更喜欢IOC方法但是如果你想要一个快速解决方案而不需要重写太多代码,你可以做这样的事情:

public class UserService : IUserService 
{
    public static Func<MyDbContext> CreateContext = () => new MyDbContext();

    public UserService ()
    {
    } 

    public void AddUser(UserModel userModel)
    {
        ...
        using (var context = CreateContext())
        {
            context.Users.Add(user);
        }
    }
}

您不必更改生产代码,但在TestMethod中可以执行

    var context = new MyDbContext
    {
        Users = userSet
    };
    UserService.CreateContext = () => context;

答案 2 :(得分:0)

您需要在服务的构造函数中传递 DbContext 。最简单的方法是开始使用任何IoC框架(AutoFac,Unity,Ninject等)。要模拟数据库,最简单的方法是开始使用任何模拟库,如Moq和RhinoMocks。

public class UserService : IUserService 
{
    private MyDbContext _context;

    public UserService (MyDbContext dbContext)
    {
        _context = dbContext;
    } 
}