2015-03-03 18 views
3

Я пытаюсь найти лучший способ сделать это - я искал ALOT в течение нескольких часов, но не могу заставить это работать. Мне нужны свежие глаза и перспектива.Основы Moq и Entity

Я пытаюсь создать прямое приложение. Он будет использовать EF 6.1.0 в качестве DAL.

У меня есть объект, называемый User. У меня есть другая организация под названием WorkItem

У пользователя может быть много WorkItems.

Я создал EFDbContext под названием «TimesheetsContext». Он наследует от DbContext и имеет 2 виртуального свойство:

public virtual IDbSet<WorkItem> WorkItems { get; set; } 

    public virtual IDbSet<User> Users { get; set; } 

Я также имею IUnitOfWork (и его конкретный класс)

public interface IUnitOfWork 
{ 
    ITimeSheetContext Context { get; set; } 
    IWorkItemRepository WorkItemRepository { get; set; } 
    IUserRepository UserRepository { get; set; } 
} 

WorkItem и хранилище пользователя просто имеют такие функции, как добавление, Логин, обновление , который, в свою очередь, вызывает EfDBContext для выполнения операции запроса.

Теперь я хочу создать единичный тест, чтобы иметь возможность макетировать DbContext и иметь возможность добавлять пользователей или рабочие элементы. Однако я не могу заставить его работать.

Однажды, с вашей помощью, я получил это далеко, я могу легко изменить его, чтобы использовать уровень сервиса и передать в IUnitOfWork.

Используя Moq и EntityFramework.Testing.Moq, я не могу заставить его работать:

private Mock<TimeSheetContext> _mockContext; 

    // <snip /> 

     Guid userId1 = Guid.NewGuid(); 
     Guid userId2 = Guid.NewGuid(); 
     Guid userId3 = Guid.NewGuid(); 
     var users = new List<User>(new[] 
     { 
      new User { Firstname = "Joe", Lastname = "Bloggs", Password = "pass1", UserId = userId1, Username = "JoeBloggs" }, 
      new User { Firstname = "Thom", Lastname = "Stevens", Password = "pass2", UserId = userId2, Username = "ThomStevens"}, 
      new User { Firstname = "Homer", Lastname = "Simpson", Password = "pass3", UserId = userId3, Username = "HomerSimpson" } 
     }).AsQueryable(); 

     var tasks = new List<LionTask>(new[] 
     { 
      new WorkItem { CreatedDate = DateTime.Today, Description = "Desc1", ModifiedDate = DateTime.Today, State = 1, TaskId = Guid.NewGuid(), Title = "Test Title", UserId = userId1 }, 
      new WorkItem { CreatedDate = DateTime.Today, Description = "Desc2", ModifiedDate = DateTime.Today, State = 2, TaskId = Guid.NewGuid(), Title = "Test Title 2", UserId = userId2 }, 
      new WorkItem { CreatedDate = DateTime.Today, Description = "Desc3", ModifiedDate = DateTime.Today, State = 3, TaskId = Guid.NewGuid(), Title = "Test Title 3", UserId = userId3 } 
     }).AsQueryable(); 

     this._mockContext = new Mock<TimeSheetContext>(); 
     var taskDbSetMock = new Mock<IDbSet<WorkItem>>(); 
     var userDbSetMock = new Mock<IDbSet<User>>(); 
     userDbSetMock.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider); 
     userDbSetMock.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression); 
     userDbSetMock.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType); 
     userDbSetMock.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator()); 

     taskDbSetMock.As<IQueryable<WorkItem>>().Setup(m => m.Provider).Returns(tasks.Provider); 
     taskDbSetMock.As<IQueryable<WorkItem>>().Setup(m => m.Expression).Returns(tasks.Expression); 
     taskDbSetMock.As<IQueryable<WorkItem>>().Setup(m => m.ElementType).Returns(tasks.ElementType); 
     taskDbSetMock.As<IQueryable<WorkItem>>().Setup(m => m.GetEnumerator()).Returns(tasks.GetEnumerator()); 

     this._mockContext.Setup(c => c.Users).Returns(userDbSetMock.Object); 
     this._mockContext.Setup(c => c.WorkItems).Returns(taskDbSetMock.Object); 

Наконец, я тогда есть тест, как это, но когда я добавить пользователя, я еще вернусь 3 и Неисправность подтверждения:

 User u = new User { Firstname = "Timmy", Lastname = "Johanson", Password = "omg123", UserId = Guid.NewGuid(), Username = "TJ" }; 
     this._mockContext.Object.Users.Add(u); 

     Assert.AreEqual(4, this._mockContext.Object.Users.Count()); 

Я собираюсь сделать это неправильно?

+0

А что, собственно, происходит? –

+0

@JohnSaunders - контекст все еще содержит 3 элемента, а не 4, когда я добавляю новый элемент пользователя. Я хочу иметь возможность сохранять и видеть какие-либо обновления/изменения при вызове fooed up context/Repository. –

+0

Это может вас заинтересовать: http://vannevel.net/blog/2015/02/26/11/ –

ответ

1

Похоже, вы пытаетесь настроить users в качестве резервного хранилища, но это не так, как работает Moq. Фиктивный возвращает то, что вы сказали ей, чтобы вернуться:

userDbSetMock.As<IQueryable<User>>().Setup(m => m.GetEnumerator()) 
    .Returns(users.GetEnumerator()); 

Если вместо этого написал:

users.Add(u); 

users.GetEnumerator() возвратит четыре пользователей вы ожидали.

Однако неясно, как это поможет вам протестировать объект, который принимает макет контекста. Я думаю, вам следует пересмотреть, как тестируется испытуемый объект, и вы можете обнаружить, что вам не нужно добавлять этот объект во время теста.

+0

Спасибо. Понял. Ну, я хочу, чтобы модуль мог тестировать запутанный контекст и убедиться, что он может добавлять/удалять/обновлять элементы. Итак, как мне изменить текущую тестовую настройку, чтобы я мог сделать это из самого метода тестирования? все издевательства выполняются по методу для [TestInitialize] до того, как тесты будут запущены. –

+0

Почему вы хотите протестировать насмешливый контекст? Разве это не похоже на тестирование, чтобы увидеть, как работает Moq? Stubs предназначены для тестирования статических контекстов. Для динамических контекстов вы можете захотеть создать собственный поддельный контекстный класс со списком в качестве хранилища резервных копий. – neontapir

+0

Вот пример такого объекта из другого вопроса: http://stackoverflow.com/questions/11787968/unit-testing-entity-framework-with-mock-idbset – neontapir

1

Непонятно, какой конкретный класс вы связываете, чтобы протестировать именно так, как вы издеваетесь над всем.

Если вы хотите протестировать ContextClass (мне кажется, что вы просто будете тестировать сторонний код, который обычно нет), тогда вам нужно будет использовать тест интеграции, который фактически попадает в базу данных.

Скорее всего, вы хотите какой-то IRepository который имеет высмеивал TimesheetsContext

public interface ITimesheetsContext 
{ 
    IDbSet<Timesheet> Timesheets { get; set; } 
} 
public interface ITimesheetRepository 
{ 
    void Add(Timesheet sheet); 
} 

public class DbTimesheetRepository : ITimesheetRepository 
{ 
    public ITimesheetsContext _context; 

    public DbTimesheetRepository(ITimesheetsContext context) 
    { 
     _context = context; 
    } 

    public void Add(Timesheet ts) 
    { 
     _context.Timesheets.Add(ts); 
    } 
} 

    [TestFixture] 
    public class DbTimesheetRepositoryTests 
    { 
     public void Add_CallsSetAdd() 
     { 
      // Arrange 
      var timesheet = new Timesheet(); 

      var timesheetsMock = new Mock<IDbSet<Timesheet>>(); 
      timesheetsMock.Setup(t => t.Add(timesheet)).Verifiable(); 

      var contextMock = new Mock<ITimesheetsContext>(); 
      contextMock.Setup(x => x.Timesheets).Returns(timesheetsMock.Object); 

      var repo = new DbTimesheetRepository(contextMock.Object); 

      // Act 
      repo.Add(timesheet); 

      // Assert 
      timesheetsMock.Verify(t => t.Add(timesheet), Times.Once); 
     }   
    } 

Чем в будущем вы можете иметь

public class ServiceTimesheetContext : ITimesheetContext { }

Какие ударяется услугу, а не Db

+0

Спасибо. Это имеет смысл. Я предполагаю, что я пытаюсь довести это до такой степени, чтобы быть в состоянии сказать, макетировать службу и вызывать ее методы, но резервный магазин будет иметь внутреннюю коллекцию вместо БД, но не уверен, как это сделать с IUnitOfWork/EfDBContext –

+0

Поэтому позвольте мне задать еще один вопрос: как бы я макетировал сервисный уровень, который в конструкторе требует интерфейс IUnitOfWork (который, в свою очередь, имеет свойства для IUserRepository и IWorkItemRepository)? как я мог бы вызывать вызовы, а также сохранять данные в памяти для модульного тестирования? –

Смежные вопросы