测试状态机

一般来说,测试状态机和状态图应该通过测试状态机的 整体行为 来完成; 那是:

给定当前状态,当某些事件序列发生时,被测系统应该处于某种状态和/或表现出特定的输出

这遵循 行为驱动开发 (BDD)黑盒测试 策略。 不应直接测试状态机的内部工作; 相反,应该测试观察到的行为。 这使得测试状态机比单元测试更接近于集成或端到端 (E2E) 测试。

测试纯逻辑

如果你不想测试副作用,例如执行操作或调用 演员,而是想测试纯逻辑,则可以使用 machine.transition(...) 函数来断言已达到特定状态 给定初始状态和事件:

  1. import { lightMachine } from '../path/to/lightMachine';
  2. it('should reach "yellow" given "green" when the "TIMER" event occurs', () => {
  3. const expectedValue = 'yellow'; // 预期状态值
  4. const actualState = lightMachine.transition('green', { type: 'TIMER' });
  5. expect(actualState.matches(expectedValue)).toBeTruthy();
  6. });

测试服务

服务的行为和输出可以通过断言它 最终 达到预期状态来测试,给定初始状态和一系列事件:

  1. import { fetchMachine } from '../path/to/fetchMachine';
  2. it('should eventually reach "success"', (done) => {
  3. const fetchService = interpret(fetchMachine).onTransition((state) => {
  4. // 这是你期望最终达到状态的地方
  5. if (state.matches('success')) {
  6. done();
  7. }
  8. });
  9. fetchService.start();
  10. // 向服务发送零个或多个事件,使其最终达到预期状态
  11. fetchService.send({ type: 'FETCH', id: 42 });
  12. });

::: tip 请记住,大多数测试框架都有一个默认超时,并且异步测试预计会在该超时之前完成。 如有必要,配置超时(例如,jest.setTimeout(timeout))用于更长时间运行的测试。 :::

模拟副作用

由于动作和调用/生成 演员 是副作用,因此在测试环境中执行它们可能是不可取的。 你可以使用 machine.withConfig(...) 选项来更改某些操作的实现细节:

  1. import { fetchMachine } from '../path/to/fetchMachine';
  2. it('should eventually reach "success"', (done) => {
  3. let userAlerted = false;
  4. const mockFetchMachine = fetchMachine.withConfig({
  5. services: {
  6. fetchFromAPI: (_, event) =>
  7. new Promise((resolve) => {
  8. setTimeout(() => {
  9. resolve({ id: event.id });
  10. }, 50);
  11. })
  12. },
  13. actions: {
  14. alertUser: () => {
  15. // 设置一个标志而不是执行原来的动作
  16. userAlerted = true;
  17. }
  18. }
  19. });
  20. const fetchService = interpret(mockFetchMachine).onTransition((state) => {
  21. if (state.matches('success')) {
  22. // 断言效果已执行
  23. expect(userAlerted).toBeTruthy();
  24. done();
  25. }
  26. });
  27. fetchService.start();
  28. fetchService.send({ type: 'FETCH', id: 42 });
  29. });