单元测试使用Moq的通用工作单元和存储库模式框架

时间:2015-03-31 02:52:29

标签: c# unit-testing async-await moq unit-of-work

我的智慧结束了。我正在学习如何使用the Generic Unit of Work and Repository pattern framework 。我设置控制器,统一和视图都没有问题......它们都可以处理实时数据。我的问题是对这些异步存储库进行单元测试。

我在这里发现了很多关于stackoverflow的帖子和MSDN中有关mocking the DataContext using Moq的文章。

然而,在执行测试时,我似乎面临着障碍,我不知道如何解决这个问题。请耐心等待。

以下是我正在测试的控制器:

public class TeamsController : Controller
{
   private readonly IUnitOfWorkAsync _uow;
   private readonly IRepositoryAsync<Team> _repo;

   public TeamsController(IUnitOfWorkAsync uow)
   {
      _uow = uow;
      _repo = _uow.RepositoryAsync<Team>();
   }

   // GET: Teams
   public async Task<ViewResult> Index()
   {
      return View(await _repo.Queryable().ToListAsync());
   }
}

以下是单元测试:

[TestMethod]
public async Task Index_AccessIndexPage_MustPass()
{
   // arrange
   var data = new List<Team> 
   { 
      new Team { Id = 1 }
   }.AsQueryable();

   Mock<DbSet<Team>> mockSet = data.GenerateMockDBSet<Team>();
   var mockContext = new Mock<IDataContextAsync>();
   mockContext.As<IDBContext>().Setup(c => c.Teams).Returns(mockSet.Object);

   _uow = new UnitOfWork(mockContext.Object);

   // act
   _controller = new TeamsController(_uow);
   var result = await _controller.Index();
   var model = (List<Team>)((ViewResult)result).Model;

   // assert
   Assert.IsNotNull(model);
   Assert.AreEqual(model.Count, 2);
}

这是我从MSDN获得的实用程序:

public static Mock<DbSet<TEnt>> GenerateMockDBSet<TEnt>(this IQueryable<TEnt> data)
            where TEnt : Entity
{
  var mockSet = new Mock<DbSet<TEnt>>();
  mockSet.As<IDbAsyncEnumerable<TEnt>>()
         .Setup(m => m.GetAsyncEnumerator())
         .Returns(new TestDbAsyncEnumerator<TEnt>(data.GetEnumerator()));

  mockSet.As<IQueryable<TEnt>>()
         .Setup(m => m.Provider)
         .Returns(new TestDbAsyncQueryProvider<TEnt>(data.Provider));

  mockSet.As<IQueryable<TEnt>>().Setup(m => m.Expression).Returns(data.Expression);
  mockSet.As<IQueryable<TEnt>>().Setup(m => m.ElementType).Returns(data.ElementType);
  mockSet.As<IQueryable<TEnt>>().Setup(m => m.Provider).Returns(data.Provider);
  mockSet.As<IQueryable<TEnt>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator);

  return mockSet;
}

以下是单元测试的实际例外:

Test method MyMVC.Tests.Controllers.TeamsControllerTest.Index_AccessIndexPage_MustPass threw exception: 
System.ArgumentNullException: Value cannot be null.
Parameter name: source
Result StackTrace:  
at System.Data.Entity.Utilities.Check.NotNull[T](T value, String parameterName)
   at System.Data.Entity.QueryableExtensions.ToListAsync[TSource](IQueryable`1 source)

在实际的.Queryable()调用期间触发了异常,因为IRepositoryAsync _repo似乎抛出了null。

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

您的控制器依赖于IUnitOfWorkAsync,以及需要嘲笑的内容。你不应该使用&#34;真实&#34;新的UnitOfWork。

我建议您为异步存储库等创建模拟:

var myData = new List<Team>(); //fill whatever test data you need

var repo = new Mock<IRepositoryAsync<Team>>();
repo.Setup(r=>r.Queryable()).Returns(myData.AsQueryable());
var uow = new Mock<IUnitOfWorkAsync>();
uow.Setup(u=>u.RepositoryAsync<Team>()).Returns(repo.Object);