2

У меня возникли проблемы с выяснением того, как издеваться над моей базой данных для модульного тестирования моих веб-контроллеров api. Все ресурсы, которые я нашел, работают для первого кода EF, но не сначала, когда мой контекст автогенерируется.Измельчение базы данных в EF6 db first

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

Я пытаюсь использовать http://www.nogginbox.co.uk/blog/mocking-entity-framework-data-context, чтобы положить его вместе, но не может управлять ...

Мой контекст определяется как:

public partial class MyEntities : DbContext 
{ 
    public MyEntities() 
     : base("name=MyEntities") 
    { 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     throw new UnintentionalCodeFirstException(); 
    } 

    public virtual DbSet<Company> Companies { get; set; } 

Теперь я понимаю, что мне нужно создать IContext, которая позволяет издевательство над MyEntities, но я не могу понять, как это организовать.

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

public interface IContext 
{ 
    IObjectSet<Company> Companies { get; } 

    void SaveChanges(); 
} 

public class EFContext: IContext 
{ 
    private readonly MyEntities _data; 

    public EFContext() 
    { 
     _data = new MyEntities(); 
    } 

    public IObjectSet<Company> Companies 
    { 
     get 
     { 
      return _data.CreateObjectSet<Company>(); 
     } 
    } 

    public void SaveChanges() 
    { 
     _data.SaveChanges(); 
    } 
} 

Пример

Пример контроллера я хотел бы модульное тестирование, которое было бы очень легко сделать, если бы я мог издеваться базу данных, чтобы проверить против.

public IHttpActionResult Search([FromBody]string query) 
    { 
     var companies = CompanyRepository.Get().Where(c => c.Name.ToLower().Contains(query.ToLower())); 
     var people = PersonRepository.Get().Where(c => c.FirstName.ToLower().Contains(query.ToLower()) || c.LastName.ToLower().Contains(query.ToLower())); 

     List<SearchResult> results = new List<SearchResult>(); 
     foreach(Company company in companies) 
      results.Add(new SearchResult { ID = company.ID, Name = company.Name, Type = "Company" }); 
     foreach (Person person in people) 
      results.Add(new SearchResult { ID = person.ID, Name = person.FirstName + " " + person.LastName, Type = "Person" }); 

     return Ok(results); 
    } 
  1. Как я могу дразнить мой EF базу данных первого контекста использовать тестовую базу данных?

ответ

3

Обновлено 11/07/2015

Таким образом, некоторые тесты, которые я могу увидеть:

  1. "Поиск должны получить компании один раз, когда запрос не пуст"
  2. «Поиск не следует получать компании, когда запрос пуст »
  3. « Поиск должен получать людей один раз, когда запрос не пуст »
  4. «Поиск не должен получить человек, когда запрос пуст»
  5. «Поиск не следует добавлять компаний, когда запрос пуст»
  6. «Поиск должен возвращать результат с одной компанией, если одна компании нашла из хранилища компании»
  7. «Поиск должен возвращать результат с двумя компаниями, если две компании найдены из репозитория компании»
  8. «Поиск не должен возвращать результат никому, когда запрос пуст»
  9. «Поиск должен возвращать результат с одним человеком, если один человек найденный из репозитория от лица "
  10. " Поиск должен быть рету в результате с двумя людьми, если два человека нашли из личного хранилища »

Итак, первое, о чем нужно подумать, это« Каковы зависимости »этого контроллера. Из этого метода я могу видеть CompanyRepository и PersonRepository. Это то, что вы хотите насмехаться. т. е. вы не тестируете их здесь или какую-либо их функциональность. Вы тестируете только то, что в вашем методе.

Вы хотите изменить свой контроллер, так что вы можете издеваться над ними, например:

public class MyController : ApiController 
{ 
    private ICompanyRepository companyRepository; 
    private IPersonRepository personRepository; 

    public MyController() 
    { 
     companyRepository = new CompanyRepository(); 
     personRepository = new PersonRepository(); 
    } 

    public MyController (ICompanyRepository CompanyRepository, IPersonRepository PersonRepository) 
    { 
     companyRepository = CompanyRepository; 
     personRepository = PersonRepository; 
    } 
} 

тогда Ваш код должен ссылаться на частные хранилища

public IHttpActionResult Search([FromBody]string query) 
{ 
    var companies = companyRepository.Get().Where(c => c.Name.ToLower().Contains(query.ToLower())); 
    var people = personRepository.Get().Where(c => c.FirstName.ToLower().Contains(query.ToLower()) || c.LastName.ToLower().Contains(query.ToLower())); 

    List<SearchResult> results = new List<SearchResult>(); 
    foreach(Company company in companies) 
     results.Add(new SearchResult { ID = company.ID, Name = company.Name, Type = "Company" }); 
    foreach (Person person in people) 
     results.Add(new SearchResult { ID = person.ID, Name = person.FirstName + " " + person.LastName, Type = "Person" }); 

    return Ok(results); 
} 

тесты затем выглядеть (в зависимости от который тестирует & фальшивый каркас, который вы используете). Пожалуйста, обратите внимание, что это довольно грубое кодирование и не будет работать, если вставили !:

[TestClass] 
public class MyControllerTests 
{ 
    Mock<ICompanyRepository>() mockCompanyRepository = new Mock<ICompanyRepository>() 
    Mock<IPersonRepository>() mockPersonRepository = new Mock<IPersonRepository>() 
    MyController sut; 

    Public MyControllerTests() 
    { 
     // Create your "System under test" which is your MyController. Pass in your mock repositories to aid your testing. 
     sut = new MyController(mockCompanyRepository.Object, mockPersonRepository.Object) 
    } 

    [TestMethod] 
    public void SearchShouldGetCompaniesOnceWhereQueryIsNotEmpty 
    { 
     //Arrange 
     var expectedCompanies = new List<Company>{new Company{"Company1"}, new Company{"Company2"}}; 
     //Setup mock that will return People list when called: 
     mockCompanyRepository.Setup(x => x.Get()).Returns(expectedCompanies); 
     mockPersonRepository.Setup(x => x.Get()).Returns(new List<Person>()) 

    //Act 
    var result = sut.Search("Conway"); 

    //Assert - check the company repository was called once and the result was as expected 
    mockCompanyRepository.Verify(x => x.Get(), Times.Once()); 

OkNegotiatedContentResult<string> conNegResult = Assert.IsType<OkNegotiatedContentResult<string>>(actionResult); 
Assert.Equal("data: [{Name : "Company1"}, {Name : "Company2"}]", conNegResult.Content); 
    } 
} 

Вы не включили код для хранилищ в вопросе, но если вы используете выше стиль, который вы должны быть в состоянии следовать такой же рисунок. Если ваш метод Get-репозитория Get не имеет логики и является просто проходом, я бы сказал, что вам не нужно писать тест против него. Если вы делаете фанки, такие как заказы, фильтрация и т. Д., То я бы сказал, что вы это делаете. Но вы затем проверяете хранилище сами по себе и очень похожим на вышеизложенное!

Быстрое примечание. Конструктор MyController имеет 2 метода. Один из них без параметров, а другой - ваши репозитории. Я сделал это, так как не знаю, используете ли вы IoC (Inversion of Control или Dependency Injection container). Вам это не нужно, но это избавит вас от необходимости писать конструкторы без параметров для всех классов, которые вы хотите протестировать.

Оригинал ответа

Я думаю, что первый вопрос: «Что вы пытаетесь проверить?». Когда вы пишете тест, он должен тестировать только функциональность в тестовой цели, а не в каких-либо зависимостях. Поэтому, возможно, вам не нужно подключаться к тестовой базе данных для запуска теста на единицу (если вы не проводите тест интеграции). Однако вам нужно будет издеваться над EF DBContext. Проверьте это MSDN article, который имеет множество примеров

+0

Спасибо @sarin. Я хочу, чтобы мои веб-контроллеры api состояли в основном из CRUD-операций. Таким образом, примерный тест может заключаться в том, чтобы добавить компанию через Add(); а затем убедитесь, что эта новая компания была добавлена. Я пытался следовать статье, которую вы связали изначально с помощью Moq, но я не мог понять, как заставить ее работать с тем, как был настроен мой DbContext (другим программистом) –

+0

ok. У вас есть несколько вариантов. Единичный тест, который ваш контроллер WebApi вызывает метод добавления на вашем объекте, когда вы ожидаете его, и только один раз. Создайте тест интеграции, чтобы сделать, как вы говорите, I.e. вызовите метод добавления и затем проверьте, были ли данные добавлены в базу данных. Создайте тест блока базы данных и проверьте свою хранимую процедуру. В качестве альтернативы ни один из вышеперечисленных. Честно говоря, для чего-то такого тривиального я бы не стал беспокоиться. Корпорация Entity Framework уже протестирована Microsoft. Класс, который вы показали выше, просто передает запрос. Для меня это не гарантирует испытание. Более сложная логика, то да. – sarin

+0

Это был простой пример, да, я обновил свой вопрос, чтобы включить более реалистичный вариант использования. Я не вижу, как единично тестировать в таком изолированном режиме, просто не тестируя макетную базу данных [которая все просто попадает через EF, как вы сказали]; но оцените предложения –

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

  • Нет связанных вопросов^_^