2015-03-31 15 views
3

Я нахожусь на своем пути. Я изучаю, как использовать the Generic Unit of Work and Repository pattern framework. У меня нет проблем с настройкой контроллеров, единством и представлениями ... все они работают с живыми данными. Моя проблема - это тестирование этих асинхронных репозиториев.Unit Testing Generic Unit of Work and Repository Рамка шаблонов с использованием Moq

Я столкнулся с многочисленными сообщениями здесь в 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, похоже, выбрасывает нуль.

Может ли кто-нибудь помочь?

+0

Вы можете редактировать свой пост и включать код для Вашего UnitOfWork? Это проще и полнее, если мы увидим его здесь inline. В частности, я хочу видеть вызовы конструктора и RepositoryAsync, потому что вы передаете mockContext в конструктор ouw. Я думаю, что в вашем TeamController ctor, '_uow.RepositoryAsync ()' вызывает что-то в вашем mockContext, который вы еще не настроили, так что результаты TeamsController._repo равны нулю при создании экземпляра класса. – Damon

+0

Привет, Дэймон, как я уже говорил. Код для UOW и Gen Repo предоставляется библиотекой с открытым исходным кодом. Это не обязательно пусто, но только часть, в которой я конвертирую ее в .Queryable(). Ура! –

+0

Мартин, я сталкиваюсь с этой же ошибкой. Мой код не совсем такой же, как ваш код, но он очень похож. Не могли бы вы ответить на вопрос, как выглядит ваш код? – Rogala

ответ

0

Ваш контроллер зависит от IUnitOfWorkAsync, и это то, что нужно издеваться. Вы не должны использовать «настоящий» новый 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); 
+0

Cheers Sunny, я, наконец, понял это: Вместо использования myData.AsQueryable() в Returns я применил это: repo.Setup (r => r.Queryable()). Возвращает (mockContext.As () .Object.Teams.AsQueryable()); –

+0

@MartinOngtangco: вы можете сделать это именно так, но ИМХО вы заходите слишком глубоко. Зачем вам нужно использовать еще один макет, который вам нужно настроить? Использование списка является более естественным, так как вы можете подготовить его намного проще и для различных тестов и/или удаления элементов по своему усмотрению. Макет будет идти вам на пути в тот момент, когда вы решите добавить предложение Where, например. –

+0

У меня возникла проблема с запросом. Это было единственное решение. благодаря –