# 测试机
¥Testing Machines
这些 XState v4 文档不再维护
XState v5 现已推出!阅读有关 XState v5 的更多信息 (opens new window)
¥XState v5 is out now! Read more about XState v5 (opens new window)
🆕 在我们的新文档中查找有关 使用 XState 进行测试 (opens new window) 的更多信息。
¥🆕 Find more about testing using XState (opens new window) in our new docs.
一般来说,测试状态机和状态图应该通过测试机器的整体行为来完成;那是:
¥In general, testing state machines and statecharts should be done by testing the overall behavior of the machine; that is:
给定当前状态,当发生某些事件序列时,被测系统应处于特定状态和/或呈现特定输出。
¥Given a current state, when some sequence of events occurs, the system under test should be in a certain state and/or exhibit a specific output.
这遵循 行为驱动开发(BDD) (opens new window) 和 黑盒测试 (opens new window) 策略。不应直接测试机器的内部工作情况;相反,应该测试观察到的行为。这使得测试机器比单元测试更接近集成或端到端(E2E)测试。
¥This follows behavior-driven development (BDD) (opens new window) and black-box testing (opens new window) strategies. The internal workings of a machine should not be directly tested; rather, the observed behavior should be tested instead. This makes testing machines closer to integration or end-to-end (E2E) tests than unit tests.
# 测试纯逻辑
¥Testing pure logic
如果你不想测试副作用(例如执行操作或调用参与者),而是想测试纯逻辑,则可以使用 machine.transition(...)
函数来断言在给定初始状态和事件的情况下达到了特定状态:
¥If you do not want to test side-effects, such as executing actions or invoking actors, and want to instead test pure logic, the machine.transition(...)
function can be used to assert that a specific state is reached given an initial state and an event:
import { lightMachine } from '../path/to/lightMachine';
it('should reach "yellow" given "green" when the "TIMER" event occurs', () => {
const expectedValue = 'yellow'; // the expected state value
const actualState = lightMachine.transition('green', { type: 'TIMER' });
expect(actualState.matches(expectedValue)).toBeTruthy();
});
# 测试服务
¥Testing services
给定初始状态和事件序列,可以通过断言服务最终达到预期状态来测试服务的行为和输出:
¥The behavior and output of services can be tested by asserting that it eventually reaches an expected state, given an initial state and a sequence of events:
import { fetchMachine } from '../path/to/fetchMachine';
it('should eventually reach "success"', (done) => {
const fetchService = interpret(fetchMachine).onTransition((state) => {
// this is where you expect the state to eventually
// be reached
if (state.matches('success')) {
done();
}
});
fetchService.start();
// send zero or more events to the service that should
// cause it to eventually reach its expected state
fetchService.send({ type: 'FETCH', id: 42 });
});
提示
请记住,大多数测试框架都有默认超时,并且异步测试预计会在该超时之前完成。如果需要 (例如,jest.setTimeout(timeout)
(opens new window)),请为运行时间较长的测试配置超时。
¥Keep in mind that most testing frameworks have a default timeout, and the async tests are expected to finish before that timeout. Configure the timeout if necessary (e.g., jest.setTimeout(timeout)
(opens new window)) for longer-running tests.
# 模拟副作用
¥Mocking effects
由于操作和调用/生成 Actor 是副作用,因此可能不希望在测试环境中执行它们。你可以使用 machine.withConfig(...)
选项更改某些操作的实现细节:
¥Since actions and invoking/spawning actors are side-effects, it might be undesirable to execute them in a testing environment. You can use the machine.withConfig(...)
option to change the implementation details of certain actions:
import { fetchMachine } from '../path/to/fetchMachine';
it('should eventually reach "success"', (done) => {
let userAlerted = false;
const mockFetchMachine = fetchMachine.withConfig({
services: {
fetchFromAPI: (_, event) =>
new Promise((resolve) => {
setTimeout(() => {
resolve({ id: event.id });
}, 50);
})
},
actions: {
alertUser: () => {
// set a flag instead of executing the original action
userAlerted = true;
}
}
});
const fetchService = interpret(mockFetchMachine).onTransition((state) => {
if (state.matches('success')) {
// assert that effects were executed
expect(userAlerted).toBeTruthy();
done();
}
});
fetchService.start();
fetchService.send({ type: 'FETCH', id: 42 });
});
← 解释机器 使用 TypeScript →