модульное тестирование с общим репозиторием moq и UnitOfWork

У меня есть специальный и общий репозиторий:

Универсальный репозиторий:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    protected readonly DbContext Context;
    private DbSet<TEntity> _entities;

    public Repository(DbContext context)
    {
        Context = context;
        _entities = Context.Set<TEntity>();
    }

    public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
    {
        return _entities.Where(predicate);
    }
}

Конкретный репозиторий:

public class HolidayCalendarRepository : Repository<HolidayCalendar>, IHolidayCalendarRepository
{
    public HolidayCalendarRepository(ApplicationDbContext context)
        : base(context)
    {
    }

    public ApplicationDbContext ApplicationDbContext
    {
        get { return Context as ApplicationDbContext; }
    }

    public bool IsHoliday(DateTime date)
    {
        return Find(h => h.Date == date.Date).Any();
    }
}

IRRepository

public interface IRepository<TEntity> where TEntity : class
{       
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
}

Репозиторий IHolidayCalendarRepository

public interface IHolidayCalendarRepository : IRepository<HolidayCalendar>
{
    bool IsHoliday(DateTime date);                     
}

Единица работы

public class UnitOfWork : IUnitOfWork
{
    private readonly ApplicationDbContext _context;

    public UnitOfWork(ApplicationDbContext context)
    {
        _context = context;          
        HolidayCalendars = new HolidayCalendarRepository(_context);
    }

    public IHolidayCalendarRepository HolidayCalendars { get; private set; }

    public int Complete()
    {
        return _context.SaveChanges();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

Как протестировать метод IsHoliday(DateTime date) в моем репозитории. Я новичок в модульном тесте. это то, что я пытаюсь, но это не работает.

[TestFixture]
public class HolidayCalendarRepositoryTests
{
    private HolidayCalendarRepository _holidayCalendarRepository;
    private Mock<DbSet<HolidayCalendar>> _mockHolidayCalendar;

    [SetUp]
    public void TestInitialize()
    {          
        var mockContext = new Mock<ApplicationDbContext>();
        _mockHolidayCalendar = new Mock<DbSet<HolidayCalendar>>();


        mockContext.Setup(hc => hc.HolidayCalendar).Returns(_mockHolidayCalendar.Object);
        _holidayCalendarRepository = new HolidayCalendarRepository(mockContext.Object);

    }

    [Test]
    public void IsHoliday_CurrentDateIsHoliday_ShouldBeTrue()
    {
        var holidays = new List<HolidayCalendar>() { new HolidayCalendar { ID = 1, Date = DateTime.Today } };

        _mockHolidayCalendar.SetSource(holidays);

        var result = _holidayCalendarRepository.IsHoliday(DateTime.Today);

        Assert.IsTrue(result);
    }
}

Метод SetSource

    public static void SetSource<T>(this Mock<DbSet<T>> mockSet, IList<T> source) where T : class
    {
        var data = source.AsQueryable();

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

person Omar AMEZOUG    schedule 21.05.2017    source источник
comment
Как я и подозревал. Некоторый совет: обновите настройку GetEnumerator(), чтобы использовать функцию .Setup(m => m.GetEnumerator()).Returns(() => data.GetEnumerator()), чтобы ее можно было перечислить несколько раз, иначе, если вы попытаетесь ее перечислить, итератор не будет сброшен и вызовет ошибки.   -  person Nkosi    schedule 23.05.2017


Ответы (1)


Основываясь на прошлом опыте, похоже, что настройка контекста была выполнена неправильно.

Repository обращается к DbSet через метод .Set<TEntity>()...

Универсальный репозиторий:

//...ctor
public Repository(DbContext context) {
    Context = context;
    _entities = Context.Set<TEntity>(); //<-- Note method used to access DbSet
}
//...

но макет был настроен с помощью открытого свойства HolidayCalendar, а не .Set<TEntity>()

Тесты репозитория HolidayCalendarRepository

mockContext
    .Setup(hc => hc.HolidayCalendar) //<-- Note the setup
    .Returns(_mockHolidayCalendar.Object);

Это необходимо настроить в соответствии с ожидаемым поведением используемого кода.

Обновите настройку, чтобы включить...

//...
mockContext
    .Setup(_ => _.Set<HolidayCalendar>())
    .Returns(_mockHolidayCalendar.Object);
//...

... это позволило бы реализации репозитория вести себя так, как ожидалось, при выполнении теста.

Здесь предполагается, что _mockHolidayCalendar.SetSource(holidays) — это своего рода метод расширения, который назначает перечисляемый/запрашиваемый поддельный источник данных фиктивной коллекции.

person Nkosi    schedule 21.05.2017