2015-09-15 3 views
5

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

Для моих модульных тестов, я использую xUnit и Moq

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

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

Смотрите здесь код, который я пытаюсь использовать:

public class SchedulerFixture 
{ 
    #region Constructors 

    public SchedulerFixture() 
    { 
     LoggerMock = new Mock<ILogger>(MockBehavior.Strict); 

     // Setup of other mocks removed for simplicity. 
    } 

    #endregion 
} 

public class SequentialTaskExecutorMock : SchedulerFixture 
{ 
    [Fact] 
    public void Should_WriteTheCorrectLogEntries_WhenTasksAreExecutedAndNotCancelled() 
    { 
     // Defines the task that needs to be executed. 
     var task = new LongRunningServiceTaskImplementation(); 

     // Built a sequence in which logs should be created. 
     var sequence = new MockSequence(); 

     LoggerMock.Setup(x => x.Information(It.IsAny<string>(), It.IsAny<string>())).Verifiable(); 

     LoggerMock.InSequence(sequence).Setup(x => x.Information("émqsdlfk", "smdlfksdmlfk")).Verifiable(); 
     LoggerMock.InSequence(sequence).Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStopped)).Verifiable(); 
     LoggerMock.InSequence(sequence).Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStarted)).Verifiable(); 
     LoggerMock.InSequence(sequence).Setup(x => x.Information(LoggingResources.LoggerTitle, string.Format(CultureInfo.InvariantCulture, LoggingResources.Logger_TaskCompleted, task.TaskName))).Verifiable(); 
     LoggerMock.InSequence(sequence).Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStopped)).Verifiable(); 

     // Setup the mock required for the tests. 
     TaskGathererMock.Setup(x => x.GetServiceTasks(LoggerMock.Object)).Returns(() => 
     { 
      return new[] { task }; 
     }); 

     // Start the scheduler. 
     Scheduler.Start(TaskGathererMock.Object, ConfigurationManagerMock.Object); 

     // Wait for 5 seconds (this simulates running the service for 5 seconds). 
     // Since our tasks execution time takes 4 seconds, all the assigned tasks should have been completed. 
     Thread.Sleep(5000); 

     // Stop the service. (We assume that all the tasks have been completed). 
     Scheduler.Stop(); 

     LoggerMock.VerifyAll(); 
    } 
} 

Таким образом, первый шаг в моем тесте настроить журналы, а затем сам тест выполняется (это вызывает вызовы к регистратору), и в конце я это проверяю.

Однако испытание проходит всегда.

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

LoggerMock.InSequence(sequence).Setup(x => x.Information("émqsdlfk", "smdlfksdmlfk")).Verifiable(); 

не выполняется нигде в моем коде.

+4

См. [Выпуск # 75] (https://github.com/Moq/moq4/issues/75), это может быть ожидаемое поведение. –

+0

@PatrickQuirk Отличная ссылка. Но если вы посмотрите комментарии к потоку с 2 января 2014 года, то будет согласовано, что есть две проблемы (что означает «ошибки» Moq). Что сложность имеет в своем коде выше, это их «проблема 1». –

ответ

1

Хотя это обязательно кажется ошибкой в ​​Moq (см. Первый комментарий к вопросу, автор Patrick Quirk), вот приблизительная идея того, что вы могли бы сделать вместо этого. Это своего рода «длинный комментарий».

сделать простой класс, как:

class SequenceTracker 
{ 
    int? state; 

    public void Next(int newState) 
    { 
     if (newState <= state) 
      Assert.Fail("Bad ordering there! States should be increasing."); 

     state = newState; 
    } 
} 

Затем использовать его как это (модифицированная версия вашего собственного кода):

public void Should_WriteTheCorrectLogEntries_WhenTasksAreExecutedAndNotCancelled() 
{ 
    // Defines the task that needs to be executed. 
    var task = new LongRunningServiceTaskImplementation(); 

    // USE THE CLASS I PROPOSE: 
    var tracker = new SequenceTracker(); 


    //LoggerMock.Setup(x => x.Information(It.IsAny<string>(), It.IsAny<string>())) 

    LoggerMock.Setup(x => x.Information("émqsdlfk", "smdlfksdmlfk")) 
     .Callback(() => tracker.Next(10)); 
    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStopped)) 
     .Callback(() => tracker.Next(20)); 
    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStarted)) 
     .Callback(() => tracker.Next(30)); 
    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, string.Format(CultureInfo.InvariantCulture, LoggingResources.Logger_TaskCompleted, task.TaskName))) 
     .Callback(() => tracker.Next(40)); 
    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStopped)) 
     .Callback(() => tracker.Next(50)); 

    // Setup the mock required for the tests. 
    TaskGathererMock.Setup(x => x.GetServiceTasks(LoggerMock.Object)).Returns(() => 
    { 
     return new[] { task }; 
    }); 

    // Start the scheduler. 
    Scheduler.Start(TaskGathererMock.Object, ConfigurationManagerMock.Object); 

    // Wait for 5 seconds (this simulates running the service for 5 seconds). 
    // Since our tasks execution time takes 4 seconds, all the assigned tasks should have been completed. 
    Thread.Sleep(5000); 

    // Stop the service. (We assume that all the tasks have been completed). 
    Scheduler.Stop(); 

    // THIS NOW WORKS BECAUSE WE ABANDONED THE 'MockSequence' APPROACH: 
    LoggerMock.VerifyAll(); 
} 

Конечно, это может быть сделано более продвинутым, если это необходимо.

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