2013-09-09 3 views
6

Я не уверен, что это возможно, но я пытаюсь выполнить тестирование тестового репозитория, использующего DbSet. Я думал, что самым простым решением было бы сделать Enumerable и заменить DbSet этим, это моя попытка.Преобразование IQueryable <T> в DbSet <T>

Я использую C#, EntityFramework, XUnit и Moq

[Fact] 
public void SomeTest() 
{ 
    //arrange 
    var mockContext = new Mock<MyDbContext>(); 
    var mockData = new List<Person> 
     { 
      new Person { Name = "Jim", Age = 47 } 
     }; 
    mockContext.Setup(db => db.Persons).Returns((DbSet<Person>)mockData.AsQueryable()); 

    var repo = PersonRepository(mockContext.Object); 

    //act 
    var result = repo.GetByFirstName("Jim"); 

    //assert 
    //do some assertion 
} 

ошибка, что выкинут он не может преобразовать тип EnumerableQuery в DbSet заявление mockContext.Returns.

Здесь что-то похожее на то, как выглядят интерфейсы.

PersonRepository.cs

public class PersonRepository: EFRepository<Person>, IPersonRepository 
{ 
    public PersonRepository(DbContext dbContext) : base(dbContext) 
    { 
    } 

    public IQueryable<Link> GetByFirstName(string name) 
    { 
     return DbSet.Where(p => p.FirstName == name); 
    } 
} 

IPersonRepository.cs

public interface IPersonRepository: IRepository<Person> 
{ 
    IQueryable<Person> GetByFirstName(string name); 
} 

IRepository.cs

public interface IRepository<T> where T : class 
{ 
    IQueryable<T> GetAll(); 
    T GetById(int id); 
    void Add(T entity); 
    void Delete(T entity); 
    void Delete(int id); 
    void Update(T entity); 
} 

EFRepository.cs

public class EFRepository<T> : IRepository<T> where T : class 
{ 
    protected DbContext DbContext { get; set; } 
    public IDbSet<T> DbSet { get; set; } 

    public EFRepository(DbContext dbContext) 
    { 
     if (dbContext == null) 
      throw new ArgumentNullException("dbContext"); 

     DbContext = dbContext; 
     DbSet = DbContext.Set<T>(); 
    } 
    ... 
} 
+0

Если вы посмотрите на определение DbSet вы увидите, что он наследует от IEnumerable , поэтому вам может понадобиться сделать абстракцию на границе раздела (IEnumerable ) уровня. – acarlon

+0

Он также наследует от IQueryable и IEnumerable. – acarlon

ответ

1

Что вы можете сделать, это переместить выражение Linq из своего хранилища в бизнес-логику и издеваться репозиторий вместо.

public interface IPersonRepository : IRepository<Person> 
{ 
    IQueryable<Person> GetAll { get; } 
} 

public class PersonRepository : EFRepository<Person>, IPersonRepository 
{ 
    // ... 

    public IQueryable<Person> GetAll 
    { 
     get { return DbSet; } 
    } 
} 

public class SomeBusinessLogicClass 
{ 
    private readonly IPersonRepository _people; 

    public SomeBusinessLogicClass(IPersonRepository people) 
    { 
     _people = people; 
    } 

    public IEnumerable<Person> GetByFirstName(string name) 
    { 
     return _people.GetAll.Where(p => p.FirstName == name); 
    } 
} 

Теперь перепишите свой тест для проверки бизнес-логики.

[Fact] 
public void SomeTest() 
{ 
    //arrange 
    var mockRepository = new Mock<IPersonRepository>(); 
    var mockData = new List<Person> 
     { 
      new Person { Name = "Jim", Age = 47 } 
     }; 
    mockRepository.Setup(x => x.GetAll).Returns(mockData); 

    var bl = new SomeBusinessLogicClass(mockRepository.Object); 

    //act 
    var result = bl.GetByFirstName("Jim"); 

    //assert 
    //do some assertion 
} 
+0

Я уточнил вопрос еще с кодом. Я не совсем понимаю, как я буду делать то, что вы говорите. Говоря в основном, чтобы открыть источник данных для моего хранилища как свойство типа IQueryable? В моей обычной реализации подключите это к DbSet и для тестирования просто бросьте свой собственный издеваемый источник данных? Есть ли недостатки в этом? –

+0

Я полностью переписал ответ на основе вашего добавленного кода. –