Подтвердить что ты не робот

Rhino Mocks - Stub. Expect vs .AssertWasCalled

Хорошо, я знаю, что было много путаницы в отношении нового синтаксиса AAA в Rhino Mocks, но я должен быть честным, от того, что я видел до сих пор, мне нравится. Он читает лучше и сохраняет некоторые нажатия клавиш.

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

У меня был следующий код:

(manager - тестируемая система, data - это интерфейс с заглушенными данными)

    [Fact]
    public void list_count_queries_data()
    {
        data.Expect(x => x.ListCount(1));
        manager.ListCount();
        data.VerifyAllExpectations();
    }

Основная цель этого теста - просто убедиться, что менеджер фактически запрашивает DAL. Обратите внимание, что DAL на самом деле даже не существует, поэтому нет "реального" значения, возвращающегося назад.

Однако это не работает, так как мне нужно изменить ожидание, чтобы иметь возвращаемое значение, например:

        data.Expect(x => x.ListCount(1)).Return(1);

Это будет работать нормально, и тест пройдет, однако. Меня смущает то, что в этот момент возвращаемое значение означает ничего. Я могу изменить его на 100, 50, 42, независимо от того, и тест всегда будет проходить?

Это заставляет меня нервничать, потому что тест должен быть явным и должен полностью терпеть неудачу, если ожидаемые условия не будут удовлетворены правильно?

Если я изменю тест на ( "1" - это ожидаемый идентификатор, с которым связан счетчик):

    [Fact]
    public void list_count_queries_data()
    {
        manager.ListCount();
        data.AssertWasCalled(x => x.ListCount(1));
    }

Все проходит отлично, и если я переключу тест на него головой на AssertWasNotCalled, он терпит неудачу, как ожидалось. Я также думаю, что он читает намного лучше, яснее о том, что тестируется и, самое главное, ПРОПУСКАЕТ И НЕИСПРАВНОСТИ как ожидалось!

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

4b9b3361

Ответ 1

Какое испытание вы пытаетесь достичь?

 

Какое поведение или состояние вы проверяете? В частности, проверяете ли вы, что соавтор (данные) имеет свой метод ListCount, называемый (тестирование на основе взаимодействия), или просто хотите, чтобы ListCount возвращал консервированное значение, чтобы управлять тестируемым классом, проверяя результат в другом месте (традиционное государственное тестирование)?

Если вы хотите установить ожидание, используйте макет и ожидание: Используйте MockRepository.CreateMock<IMyInterface>() и myMock.Expect(x => x.ListCount())

Если вы хотите заглушить метод, используйте MockRepository.CreateStub<IMyInterface>() и myStub.Stub(x => x.ListCount()).

(в сторону: я знаю, что вы можете использовать stub.AssertWasCalled() для достижения того же самого, что и mock.Expect и, возможно, лучшего синтаксиса чтения, но я просто сверлю разницу между mocks и stub).

У Роя Ошерове очень хорошее объяснение макетов и окурков.

Пожалуйста, напишите больше кода!

Нам нужна полная картина того, как вы создаете заглушку (или макет) и как результат используется в отношении тестируемого класса. Имеет ли ListCount входной параметр? Если да, то что он представляет? Тебя это волнует, если он был вызван с определенной ценностью? Вам не нравится, если ListCount возвращает определенное значение?

Как отметил Саймон Ларош, если менеджер на самом деле ничего не делает с издеваемым/заглубленным возвратным значением ListCount, тогда тест не пройдет или не сработает из-за этого. Все тесты ожидали бы, что метод издевательства /stubbed называется - не более того.

Чтобы лучше понять проблему, рассмотрите три части информации, и вы скоро это поймете:

  • Что тестируется
  • В какой ситуации?
  • Каков ожидаемый результат?

Для сравнения: Тестирование на основе взаимодействия с помощью mocks. Призыв к макету -.

[Test]
public void calling_ListCount_calls_ListCount_on_DAL()
{
   // Arrange
   var dalMock = MockRepository.Mock<IDAL>();
   var dalMock.Expect(x => x.ListCount()).Returns(1);
   var manager = new Manager(dalMock);

   // Act
   manager.ListCount();

   // Assert -- Test is 100% interaction based
   dalMock.VerifyAllExpectations();   
}

Проверка состояния с помощью заглушки. Заглушка управляет тестом, но не является частью ожидания.

[Test]
public void calling_ListCount_returns_same_count_as_DAL()
{
   // Arrange
   var dalStub = MockRepository.Stub<IDAL>();
   var dalStub.Stub(x => x.ListCount()).Returns(1);
   var manager = new Manager(dalMock);

   // Act
   int listCount = manager.ListCount();

   // Assert -- Test is 100% state based
   Assert.That(listCount, Is.EqualTo(1),
       "count should've been identical to the one returned by the dal!");
}

Я лично предпочитаю тестирование на основе состояния, где это возможно, хотя для API, которые разработаны с использованием часто требуется тестирование на основе взаимодействия, > Tell, Do Ask в виду, поскольку у вас не будет никакого открытого состояния для проверки!

Путаница API. Маки не являются заглушками. Или они?

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

... Однако API-интерфейс Rhino Mocks является мощным, но запутанным, поскольку он позволяет вам устанавливать ожидания на заглушки, которые, как мне кажется, противоречат принятой терминологии. Я тоже не думаю о терминологии, ум. Было бы лучше, если бы различие было устранено, и методы, называемые двойным испытанием, задавали роль, на мой взгляд.

Ответ 2

Я думаю, что это связано с тем, что делает ваш менеджер .ListCount() с возвращаемым значением.

Если он не использует его, ваш DAL может вернуть что-либо, что не имеет значения.

public class Manager
{
    public Manager(DAL data)
    { 
        this.data = data
    }
    public void ListCount()
    {
        data.ListCount(1); //Not doing anything with return value
        DoingSomeOtherStuff();
    }    
}

Если ваш счетчик списков делает что-то со значением, вы должны затем ставить утверждения о том, что он делает. Например,

Assert.IsTrue(manager.SomeState == "someValue");

Ответ 3

Пробовали ли вы использовать

data.AssertWasCalled(x => x.ListCount(1) = Arg.Is(EXPECTED_VALUE));