Я нахожусь на своем пути. Я изучаю, как использовать 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, похоже, выбрасывает нуль.
Может ли кто-нибудь помочь?
Вы можете редактировать свой пост и включать код для Вашего UnitOfWork? Это проще и полнее, если мы увидим его здесь inline. В частности, я хочу видеть вызовы конструктора и RepositoryAsync, потому что вы передаете mockContext в конструктор ouw. Я думаю, что в вашем TeamController ctor, '_uow.RepositoryAsync()' вызывает что-то в вашем mockContext, который вы еще не настроили, так что результаты TeamsController._repo равны нулю при создании экземпляра класса. –
Damon
Привет, Дэймон, как я уже говорил. Код для UOW и Gen Repo предоставляется библиотекой с открытым исходным кодом. Это не обязательно пусто, но только часть, в которой я конвертирую ее в .Queryable(). Ура! –
Мартин, я сталкиваюсь с этой же ошибкой. Мой код не совсем такой же, как ваш код, но он очень похож. Не могли бы вы ответить на вопрос, как выглядит ваш код? – Rogala