【问题标题】:Start State Machine in specific state while testing测试时以特定状态启动状态机
【发布时间】:2021-07-29 09:01:33
【问题描述】:

我正在尝试为我的状态机创建单元测试,以检查每个状态是否完成了它应该做的事情。

我可以通过发布启动状态机的事件并创建达到所需状态所需的所有变量来使状态机进入任何状态。

简化状态机:

 public class CheckFilesStateMachine : MassTransitStateMachine<DataState>, ICheckFilesStateMachine
    {
        #region Events
        public Event<IEventCheckFile> CheckFile { get; private set; }
        #endregion

        #region States
        
        public State CheckingForFiles { get; }

        public State ValidatingFiles { get; }

        public State NoFilesFound { get; }

        public State Validated { get; }

        public State FilesProcessed { get; }

        public State ValidationFailed{ get; }

        #endregion

        public DataStateMachine(IDataService dataService)
        {
            InstanceState(x => x.CurrentState);

            Event(() => CheckFile, x => x.CorrelateById(context => context.Message.Id));

            Initially(When(CheckFile).TransitionTo(CheckingForFiles));

            WhenEnter(CheckingForFiles, binder => binder
                .Then(x => x.Instance.Files= dataService.GetFiles())
                .IfElse(x => dataService.HasFiles(),
                        x => x.TransitionTo(ValidatingFiles),
                        x => x.TransitionTo(NoFilesFound))
                .Catch<Exception>(ex => ex
                    .Then(x => Console.WriteLine(x.Exception.Message))));

            WhenEnter(ValidatingFiles, binder => binder
                .IfElse(x => dataService.ValidateFiles(),
                        x => x.TransitionTo(Validated),
                        x => x.TransitionTo(ValidationFailed))
                .Catch<Exception>(ex => ex
                    .Then(x => Console.WriteLine(x.Exception.Message))));

            WhenEnter(NoFilesFound, binder => binder.Then(x => Console.WriteLine("No Files found")).Finalize());
            WhenEnter(Validated, binder => binder.Then(x => Console.WriteLine("Validated")).Finalize());
            WhenEnter(ValidationFailed, binder => binder.Then(x => Console.WriteLine("Validation Failed")).Finalize());

            SetCompletedWhenFinalized();
        }
    }

我编写了一些单元测试,我可以启动机器(按照 MassTransit 文档中的 this guide),但我想检查状态 CheckingForFilesValidatingFiles正在做他们应该做的事情,彼此独立。

到目前为止,我可以通过跟随状态机的流程来模拟 IDataService 方法以达到所需的状态,但是有没有办法启动状态机并跳转到特定状态?

更新

假设我在那里有另一个状态:

 public class CheckFilesStateMachine : MassTransitStateMachine<DataState>, ICheckFilesStateMachine
    {
        #region Events
        public Event<IEventCheckFile> CheckFile { get; private set; }
        #endregion

        #region States
        
        public State CheckingForFiles { get; }

        public State ValidatingFiles { get; }

        public State DeletingFiles{ get; }

        public State NoFilesFound { get; }

        public State Validated { get; }

        public State FilesProcessed { get; }

        public State ValidationFailed{ get; }

        #endregion

        public DataStateMachine(IDataService dataService)
        {
            InstanceState(x => x.CurrentState);

            Event(() => CheckFile, x => x.CorrelateById(context => context.Message.Id));

            Initially(When(CheckFile).TransitionTo(CheckingForFiles));

            WhenEnter(CheckingForFiles, binder => binder
                .Then(x => x.Instance.Files= dataService.GetFiles())
                .IfElse(x => dataService.HasFiles(),
                        x => x.TransitionTo(ValidatingFiles),
                        x => x.TransitionTo(NoFilesFound))
                .Catch<Exception>(ex => ex
                    .Then(x => Console.WriteLine(x.Exception.Message))));

            WhenEnter(ValidatingFiles, binder => binder
                .IfElse(x => dataService.ValidateFiles(),
                        x => x.TransitionTo(Validated),
                        x => x.TransitionTo(DeletingFiles))
                .Catch<Exception>(ex => ex
                    .Then(x => Console.WriteLine(x.Exception.Message))));

            WhenEnter(DeletingFiles, binder => binder
                .Then(x => x.Instance.Files= dataService.RemoveFiles())
                .TransitionTo(ValidationFailed)
                .Catch<Exception>(ex => ex
                    .Then(x => Console.WriteLine(x.Exception.Message))));

            WhenEnter(NoFilesFound, binder => binder.Then(x => Console.WriteLine("No Files found")).Finalize());
            WhenEnter(Validated, binder => binder.Then(x => Console.WriteLine("Validated")).Finalize());
            WhenEnter(ValidationFailed, binder => binder.Then(x => Console.WriteLine("Validation Failed")).Finalize());

            SetCompletedWhenFinalized();
        }
    }

在这种情况下,我可以输入CheckingForFiles然后跳转到DeletingFiles吗?有可能吗?

【问题讨论】:

    标签: c# xunit masstransit automatonymous


    【解决方案1】:

    如果您使用基于容器的内存中测试工具,您可以从容器中解析 saga 字典并添加一个实例:

    var dictionary = provider.GetRequiredService<IndexedSagaDictionary<DataState>>();
    
    dictionary.Add(new SagaInstance<DataState>(new DataState() 
    {
        CorrelationId = dataId,
        CurrentState = "CheckingForFiles" 
    }));
    

    【讨论】:

    • 这又给我提出了两个问题。首先,在这种情况下如何启动机器?通过简单地发布事件?其次,我更新了最初的问题。谢谢!
    • 是的,发布活动。查看Season 2 Sample 了解如何实现的示例。
    • 发布事件似乎会启动状态机,而不会跟踪通过 IndexedSagaDictionary 提供的选项。
    • 如果您 followed this example 并且您的事件与正确的 saga 实例相关,那么它应该存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    相关资源
    最近更新 更多