试图了解MockSequence

Com*_*ity 6 c# moq

我正在编写一个应用程序并测试它的正确行为我需要验证方法是否按给定顺序调用.

对于我的单元测试,我正在使用 xUnitMoq

现在,为什么我需要测试调用的顺序?

我正在开发一个在不同线程上执行任务的解决方案.一旦执行任务,我就会向给定的记录器写一条消息,因此通过检查记录器调用的顺序,我确信我的代码是正确实现的.

在这里看到我正在尝试使用的代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,我测试的第一步是设置日志,然后执行测试本身(这会导致调用记录器),最后我正在验证它.

但是,测试总是通过.

在这种情况下它应该失败,因为以下调用:

LoggerMock.InSequence(sequence).Setup(x => x.Information("émqsdlfk", "smdlfksdmlfk")).Verifiable();
Run Code Online (Sandbox Code Playgroud)

不在我的代码中的任何地方执行.

Jep*_*sen 2

虽然这确实感觉像是 Moq 中的一个错误(请参阅 Patrick Quirk 对问题的第一条评论),但这里是您可以做什么的粗略想法。这是一个“长评论”。

\n\n

创建一个简单的类,例如:

\n\n
class SequenceTracker\n{\n    int? state;\n\n    public void Next(int newState)\n    {\n        if (newState <= state)\n            Assert.Fail("Bad ordering there! States should be increasing.");\n\n        state = newState;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后像这样使用它(您自己的代码的修改版本):

\n\n
public void Should_WriteTheCorrectLogEntries_WhenTasksAreExecutedAndNotCancelled()\n{\n    // Defines the task that needs to be executed.\n    var task = new LongRunningServiceTaskImplementation();\n\n    // USE THE CLASS I PROPOSE:\n    var tracker = new SequenceTracker();\n\n\n    //LoggerMock.Setup(x => x.Information(It.IsAny<string>(), It.IsAny<string>()))\n\n    LoggerMock.Setup(x => x.Information("\xc3\xa9mqsdlfk", "smdlfksdmlfk"))\n        .Callback(() => tracker.Next(10));\n    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStopped))\n        .Callback(() => tracker.Next(20));\n    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStarted))\n        .Callback(() => tracker.Next(30));\n    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, string.Format(CultureInfo.InvariantCulture, LoggingResources.Logger_TaskCompleted, task.TaskName)))\n        .Callback(() => tracker.Next(40));\n    LoggerMock.Setup(x => x.Information(LoggingResources.LoggerTitle, LoggingResources.Logger_ServiceStopped))\n        .Callback(() => tracker.Next(50));\n\n    // Setup the mock required for the tests.\n    TaskGathererMock.Setup(x => x.GetServiceTasks(LoggerMock.Object)).Returns(() =>\n    {\n        return new[] { task };\n    });\n\n    // Start the scheduler.\n    Scheduler.Start(TaskGathererMock.Object, ConfigurationManagerMock.Object);\n\n    // Wait for 5 seconds (this simulates running the service for 5 seconds).\n    // Since our tasks execution time takes 4 seconds, all the assigned tasks should have been completed.\n    Thread.Sleep(5000);\n\n    // Stop the service. (We assume that all the tasks have been completed).\n    Scheduler.Stop();\n\n    // THIS NOW WORKS BECAUSE WE ABANDONED THE \'MockSequence\' APPROACH:\n    LoggerMock.VerifyAll();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

当然,如果需要的话,这可以变得更先进。

\n