Что путь состоит в том, чтобы пойти для фальсифицирования моего слоя базы данных в модульном тесте?

У меня есть вопрос о поблочном тестировании.

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

//code a bit shortened
public actionresult Create(Formcollection formcollection){
    client c = nwe client();
    c.Name = formcollection["name"];
    ClientService.Save(c);
{

Clientservice назвал бы объект datalayer и сохранил бы его в базе данных.

Что я делаю теперь, создают базу данных testscript и устанавливают мою базу данных в знать условии перед тестированием. Таким образом, когда я тестирую этот метод в модульном тесте, я знаю, что должен быть еще один клиент в базе данных, и каково ее имя. Короче говоря:

ClientController cc = new ClientController();
cc.Create(new FormCollection (){name="John"});
//i know i had 10 clients before
assert.areEqual(11, ClientService.GetNumberOfClients());
//the last inserted one is John
assert.areEqual("John", ClientService.GetAllClients()[10].Name);

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

Но затем конечно, мои утверждения не будут работать потому что, если я скажу GetNumberOfClients() это будет всегда возвращаться X, потому что это не имеет никакого взаимодействия с поддельным классом базы данных, используемым в Создать Методе.

Я могу также создать Список Клиентов в поддельном классе базы данных, но поскольку будет два различных созданные экземпляра (один в действии контроллера и один в модульном тесте), у них не будет взаимодействия.

Что путь состоит в том, чтобы заставить этот модульный тест работать без базы данных?

Править: clientservice не соединяется непосредственно с DB. Это называет ClientDataClass, который соединится с базой данных. Таким образом, ClientDatabaseClass будет заменен фальшивкой

5
задан Michel 22 April 2010 в 07:42
поделиться

4 ответа

В этом конкретном случае вы тестируете контроллер изолированно от базы данных. ClientService - это абстракция над базой данных, и ее следует заменить на test double. Вы внедрили фальшивку в контроллер, но по-прежнему утверждаете реальную реализацию. Это не имеет никакого смысла.

Утвердить тот же объект, который был внедрен в контроллер.

 interface IClientService 
    {
      public void GetNumberOfClients();
      public IList<Client> GetAllClients();
      public void Insert(Client client);
    }

Реализация фальшивого сервиса:

   class FakeClientService : IClientService
   {
     private IList<CLient> rows = new List<CLient>();

     public void GetNumberOfClients()
     { 
       return list.Count;
     }

     public IList<Client> GetAllClients()
     {
       return list;
     }

     public void Insert(Client client)
     {
       client.Add(client);
     }
   }

Тест:

[Test]
public void ClientIsInserted()
{
  ClientController cc = new ClientController();
  FakeClientService fakeService = new FakeClientService();

  cc.ClientService = fakeService;

  cc.Create(new FormCollection (){name="John"});

  assert.areEqual(1, fakeService.GetNumberOfClients());
  assert.areEqual("John", fakeService.GetAllClients()[0].Name);
}

Если вы хотите проверить, как контроллер и сервис работают вместе - создайте фальшивку для ClientDatabaseClass. Это будет примерно так:

[Test]
public void ClientIsInserted()
{
  ClientController cc = new ClientController();
  IClientDatabaseClass databaseFake = new ClientDatabaseClassFake();

  ClientService service= new ClientService();

  service.Database = databaseFake;
  cc.ClientService = service;

  cc.Create(new FormCollection (){name="John"});

  assert.areEqual(1, service.GetNumberOfClients());
  assert.areEqual("John", service.GetAllClients()[0].Name);
}
5
ответ дан 14 December 2019 в 01:04
поделиться

Возможно, вы могли бы сделать свой поддельный класс БД Serialiseable и загружать его каждый раз из одного места. Это позволит вам сохранить данные в нем, так что он будет вести себя так, как если бы это была база данных, но на самом деле она не была бы таковой.

1
ответ дан 14 December 2019 в 01:04
поделиться

Используйте внедрение зависимостей и вместо обращения к базе данных создайте репозиторий и используйте его (по крайней мере, так Я делаю это, когда дело доходит до модульного тестирования)

edit: Это почти тот же ответ, что и ответ Стива Найта, только намного короче :)

1
ответ дан 14 December 2019 в 01:04
поделиться

Вот где, на мой взгляд, юнит-тестирование становится трудным.

Раньше я делал это эффективно, абстрагируя всю базу данных. Как вы это сделаете, будет зависеть от того, что вы пытаетесь сделать, потому что базы данных, очевидно, довольно универсальны. В вашем конкретном примере что-то вроде следующего:

public interface IDatabase<T>
{
    void Create(T value);
    int Count { get; }
    T[] All { get; }
}

Затем вы реализуете этот интерфейс с помощью некоторого простого контейнера в памяти, а затем снова реализуете его с использованием реальных средств доступа к базе данных. Контейнер в памяти часто называют «тестовым двойником».

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

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

2
ответ дан 14 December 2019 в 01:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: