Практика модульного тестирования с использованием Linq to SQL - PullRequest
4 голосов
/ 10 января 2011

Я пытаюсь обернуть голову вокруг модульного тестирования, и я столкнулся с поведением, в котором я не уверен:

«Может сделать резервную копию инвентаризации»

По сути, «Таблица «Инвентарь» копируется в таблицу «InventoryHistory» и получает отметку времени, когда произошло резервное копирование («HistoryDate»).

Вот код для резервного копирования инвентаризации:

        DateTime historyDate = DateTime.Now;
        MyDataContext db = new MyDataContext();

        db.GetTable<InventoryHistory>().InsertAllOnSubmit(
            db.GetTable<Inventory>()
                .Select(i => new InventoryHistory
                {
                    ID = i.ID,
                    ItemName = i.ItemName,
                    /* etc, etc, etc */
                    HistoryDate = historyDate

                })
        );

Мои вопросы:

  1. Должно ли / может ли это поведение быть разбито на меньшие части, проверяемые модулем?

  2. Поскольку я тестируюпротив выделенной тестовой базы данных, должен ли я использовать инструмент для проверки и следовать шаблону абстрактной фабрики для любых «репозиториев»?

Ответы [ 4 ]

2 голосов
/ 10 января 2011

Вопрос, который я хотел бы задать, заключается в том, что это действительно модульный тест?В модульном тесте будут рассматриваться макеты Table<TEntity> экземпляров, потому что нас не интересуют реальные данные, скорее, механизм создания элементов корректен.

В приведенном выше фрагменте кода вы, похоже, проводите модульное тестирование самих методов Linq, а не какого-либо конкретного кода, который вы написали сами.

Что касается вашего последнего вопроса, одна из фундаментальных ошибок сделанас насмешкой является предположение что проверить при издевательстве.Как правило, вы будете издеваться над тем, что потребляет тот тип, который вы хотите проверить.Например:

public ICalculatorService
{
  int Add(int a, int b);
}

[Test]
public void CannAdd()
{
  var mock = Mock<ICalculatorService();
  mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>()))
      .Returns(100);

  var service = mock.Object;
  Assert(service.Add(1, 2) == 100); // Incorrect
}

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

public class Calculator
{
  private readonly ICalculatorService _service;

  public Calculator(ICalculatorService service)
  {
    _service = service;
  }

  public int Add(int a, int b)
  {
    return _service.Add(a, b);
  }
}

[Test]
public void CannAdd()
{
  var mock = Mock<ICalculatorService();
  mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>()))
      .Returns(100);

  var calculator = new Calculator(mock.Object);
  Assert(calculator.Add(1, 2) == 100); // Correct
}

Это больше похоже на это (хотя и упрощенный пример).Сейчас я тестирую самого потребителя Calculator, а не расходного материала.В вашем примере, даже если бы вы издевались над своим DataContext, чтобы он возвращал фиктивные экземпляры Table<TEntity>, какие реальные преимущества вы получаете?

Реально вы, вероятно, создали бы репозиторий, например, IInventoryRepository, и создали быпотребитель этого хранилища (это может быть модель домена, контроллер и т. д.).Затем, выполнив тестирование, вы смоделируете этот репозиторий и протестируете своего потребителя.

0 голосов
/ 10 января 2011

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

  1. Извлечь метод для получения списка запасов для резервного копирования

    IQueryable GetInventoryForBackup (этот контекст DataContext) {returncontext.GetTable ();}

  2. Метод извлечения для преобразования Inventory в InventoryHistory

    IEnumerable ToInventoryHistory (это IEnumerable data, DateTime historyDate) {return data.Select (i => new InventoryHistroy {ID =)i.Id ....}

  3. Извлечь метод для сохранения последовательности InventoryHistory

    void SaveHistory (IEnumerable data) {dataContext.InsertAllOnSubmit (data); dataContext.SubmitChanges();}

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

0 голосов
/ 10 января 2011

В целях полного раскрытия, я только начинаю изучать EF и LINQ и лучший способ их тестирования, так что вы можете получить более полезную информацию о них, в частности, так что это всего лишь общие ответы тестирования.

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

ID = i.ID,
ItemName = i.ItemName,
/* etc, etc, etc */
HistoryDate = historyDate

, подвергнутого рефакторингу в отдельный метод для модульного тестирования, поскольку единственным другим кодом является LINQзвонки, которые MS отвечает за тестирование.

2.Я не думаю, что вы сможете ввести шов , чтобы изолировать его с помощью шаблона фабрики абстрактного хранилища, так как вы вызываете текстовый текст.

Я не уверенследует ли вам подделать это (и поскольку вы будете тестировать против него, это будет макет собственно - фальшивка, с которой вы тестируете, фальшивка, с которой вы не тестируете заглушка ), но так как он вызывает тестовый сервер, вы можете сделать его автоматизированным интеграционным тестом , поскольку функциональность включает взаимодействие с хранилищем данных.

0 голосов
/ 10 января 2011

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

Юнит-тестирование не затрагивает базу данных - это интеграция тестирование. Если вам нужен хороший модульный тест для этого, вы должны проверить поведение - в этом случае, что история резервируется, когда она должна быть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...