Erw*_*ers 0 c# unit-testing entity-framework dependency-injection asp.net-mvc-4
我正在寻找一种方法,在具有Entity Framework的MVC4应用程序中拥有单独的业务逻辑层,而无需在其中注入我的(真实或虚假)数据库上下文.现在我们有一个假的,真实的数据库上下文,它来自IContext一个存储库Repository和一个控制器MyController.IContext使用以下模式将注入到控制器和存储库中:
public class MyController : Controller
{
readonly Repository _repo;
/// <summary>
/// Initializes a new instance of the <see cref="Controllers.MyController"/> class which
/// makes use of the real Entity Framework context that connects with the database.
/// </summary>
public MyController()
{
_repo = new Repository();
}
/// <summary>
/// Initializes a new instance of the <see cref="Controllers.MyController"/> class which
/// can make use of a "Fake" Entity Framework context for unit testing purposes.
/// </summary>
/// <param name="db">Database context.</param>
public MyController(IContext db)
{
_repo = new Repository(db);
}
(...)
}
Run Code Online (Sandbox Code Playgroud)
这是这样设置的,因为它是具有访问数据库并需要伪上下文的方法的存储库,而单元测试针对控制器并且需要实例化.
现在我正在寻找一种方法来向项目添加业务逻辑类,其中将放置具有业务逻辑的方法.这些方法也需要从数据访问层(Repository)获得的信息.
使用上述模式在此业务逻辑层中注入IContextfor 感觉有点奇怪Repository.例如,
BusinessLogic(IContext db)
{
_repo = new Repository(db);
}
Run Code Online (Sandbox Code Playgroud)
我看到两种方法来避免这个问题:
我正在寻找一个好主意,建立与数据访问相关的业务逻辑层,并提供单元可测试性,最好不必在每个类中注入数据库上下文.
希望有人能为我提供一些见解.谢谢.
小智 5
如果要使用EF6,则具有继承自IContext或DbContext的EF上下文
public class UserContext : DbContext
{
DbSet<User> users { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
您不希望将上下文直接注入Controler.
使用Service/DAO/Repository,它在构造函数中获取IContext/DbContext实例并处理数据访问.在我的示例中,我使用IUserService接受上下文并按ID返回用户.
public interface IUserService
{
User GetUserByID(int userId);
}
public class UserService : IService
{
private readonly UserContext _context;
//Inject your mock or real context here
public UserService(UserContext context)
{
this._context = context;
}
//Implement IUserService
public User GetUserByID(int userId)
{
_context.Users.Where(u=>u.ID==userId).FirstOrDefault();
}
}
Run Code Online (Sandbox Code Playgroud)
然后通过接口将服务注入控制器.
public class UserController : Controller
{
private readonly IUserService _service;
//Consider using a Dependency injection framework e.g. Unity
public UserController(IUserService service)
{
this.service = service;
}
//The method that is tightly coupled to the view and uses the service
[HttpGet]
public ActionResult GetUserByID(int id)
{
return View(_service.GetUserById(id));
}
}
Run Code Online (Sandbox Code Playgroud)
另外,考虑使用模拟框架来模拟您的上下文,例如Moq
[TestMethod]
public void UserServiceTest()
{
//Initialize your Mock Data
var testDataUser = new List<Users>
{
new User{
ID = 1,
Name = "MockUser"
}
}.AsQueryable();
//Initialize the Mock DbSet
var mockSetUser = new Mock<DbSet<User>>();
mockSetUser.As<IQueryable<User>>().Setup(m => m.Provider).Returns(testDataUser. .Provider);
mockSetUser.As<IQueryable<User>>().Setup(m => m.Expression).Returns(testDataUser .Expression);
mockSetUser.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(testDataUser .ElementType);
mockSetUser.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(testDataUser .GetEnumerator());
//Initialize the mock Context
var mockContext = new Mock<UserContext>();
//Return the mock DbSet via the mock context
mockContext.Setup(c => c.Users).Returns(mockSetUser.Object);
//Create the service and inject the mock context
var userService = new UserService(mockContext.Object)
//Test your context via the service
var user = userService.GetUserByID(1);
Assert.AreEqual("MockUser", user.Name);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
913 次 |
| 最近记录: |