如何在使用 Boost MSM 编写的状态机中直接到达任何状态
How to reach directly any state in a state-machine written with Boost MSM
我目前正在使用 Boost MSM 库编写状态机,我想编写单元测试来检查其状态之间的转换。对于每个单元测试,我都需要编写重复的代码行以达到我想要开始的状态。因此我想知道他们是否是一种在给定状态而不是起始状态下启动状态机的方法。
例如,如果我有一个像这样的简单状态机,通常从 StartingState 开始,我想直接到达 IdleState 进行测试:
- --> StartingState --> IdleState --> ErrorState
Boost.MSM 不直接支持您想要的功能。
但是您可以使用 initial_state
内部类型和预处理器宏来控制初始状态。
假设您的状态机定义在 sm1.hpp
。
sm1.hpp
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// ----- Events
struct Event1 {};
// Test helper code
#if !defined(TEST_SM1_STATE)
#define TEST_SM1_STATE StartingState
#endif //!defined(TEST_SM1_STATE)
// ----- State machine
struct Sm1_:msmf::state_machine_def<Sm1_> {
// States
struct StartingState:msmf::state<> {
// Entry action
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "StartingState::on_entry()" << std::endl;
}
};
struct IdleState:msmf::state<> {
// Entry action
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "IdleState::on_entry()" << std::endl;
}
};
struct ErrorState:msmf::state<> {
// Entry action
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "ErrorState::on_entry()" << std::endl;
}
};
// Set initial state
using initial_state = TEST_SM1_STATE;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < StartingState, Event1, IdleState, msmf::none, msmf::none >,
msmf::Row < IdleState, Event1, ErrorState, msmf::none, msmf::none >
> {};
};
// Pick a back-end
typedef msm::back::state_machine<Sm1_> Sm1;
test.cpp
#define TEST_SM1_STATE IdleState
#include "sm1.hpp"
int main() {
Sm1 sm1;
sm1.start();
}
演示:https://wandbox.org/permlink/dnLrAZ7fTJhg473q
重点是下面的代码:
// Set initial state
using initial_state = TEST_SM1_STATE;
您可以将任何状态设置为初始状态。
在包含 sm1.hpp
之前定义初始状态,如下所示:
#define TEST_SM1_STATE IdleState
#include "sm1.hpp"
我目前正在使用 Boost MSM 库编写状态机,我想编写单元测试来检查其状态之间的转换。对于每个单元测试,我都需要编写重复的代码行以达到我想要开始的状态。因此我想知道他们是否是一种在给定状态而不是起始状态下启动状态机的方法。
例如,如果我有一个像这样的简单状态机,通常从 StartingState 开始,我想直接到达 IdleState 进行测试:
- --> StartingState --> IdleState --> ErrorState
Boost.MSM 不直接支持您想要的功能。
但是您可以使用 initial_state
内部类型和预处理器宏来控制初始状态。
假设您的状态机定义在 sm1.hpp
。
sm1.hpp
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// ----- Events
struct Event1 {};
// Test helper code
#if !defined(TEST_SM1_STATE)
#define TEST_SM1_STATE StartingState
#endif //!defined(TEST_SM1_STATE)
// ----- State machine
struct Sm1_:msmf::state_machine_def<Sm1_> {
// States
struct StartingState:msmf::state<> {
// Entry action
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "StartingState::on_entry()" << std::endl;
}
};
struct IdleState:msmf::state<> {
// Entry action
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "IdleState::on_entry()" << std::endl;
}
};
struct ErrorState:msmf::state<> {
// Entry action
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "ErrorState::on_entry()" << std::endl;
}
};
// Set initial state
using initial_state = TEST_SM1_STATE;
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < StartingState, Event1, IdleState, msmf::none, msmf::none >,
msmf::Row < IdleState, Event1, ErrorState, msmf::none, msmf::none >
> {};
};
// Pick a back-end
typedef msm::back::state_machine<Sm1_> Sm1;
test.cpp
#define TEST_SM1_STATE IdleState
#include "sm1.hpp"
int main() {
Sm1 sm1;
sm1.start();
}
演示:https://wandbox.org/permlink/dnLrAZ7fTJhg473q
重点是下面的代码:
// Set initial state
using initial_state = TEST_SM1_STATE;
您可以将任何状态设置为初始状态。
在包含 sm1.hpp
之前定义初始状态,如下所示:
#define TEST_SM1_STATE IdleState
#include "sm1.hpp"