Skip to main content
Version: Latest

Mock Mode Guide

Understanding Mock Mode in Brobot

Brobot's mock mode provides a powerful testing framework that simulates GUI automation without requiring actual screen interaction. This is essential for:

  • CI/CD pipelines where GUI access is unavailable
  • Unit testing automation logic without GUI dependencies
  • Development when the target application is unavailable
  • Testing state transitions and automation flow logic

Core Concepts

What Mock Mode Does

When mock mode is enabled (via MockModeManager.setMockMode(true) or properties):

  1. No screen capture - Brobot doesn't capture actual screens
  2. No real pattern matching - Image patterns aren't matched against real screens
  3. Probabilistic simulation - States and patterns are "found" based on configured probabilities
  4. State-based testing - Focus on testing state transitions and automation logic

State Probabilities

State probabilities determine how often a state's objects (images, regions, etc.) are "found" during mock execution:

  • 100% probability: State objects are always found (deterministic testing)
  • 0% probability: State objects are never found (failure testing)
  • 1-99% probability: Stochastic testing for robustness

Configuration

Enabling Mock Mode

Brobot now provides a centralized MockModeManager class that ensures consistency across all components:

import io.github.jspinak.brobot.config.MockModeManager;

// Enable mock mode globally
MockModeManager.setMockMode(true);

// Check if mock mode is enabled
if (MockModeManager.isMockMode()) {
// Mock-specific logic
}

// Log current mock mode state across all components
MockModeManager.logMockModeState();

The MockModeManager automatically synchronizes mock mode across:

  • System properties (brobot.mock.mode, brobot.framework.mock, brobot.core.mock-mode)
  • ExecutionEnvironment (for runtime behavior)
  • FrameworkSettings.mock (for SikuliX compatibility)

Configuration via Properties

You can also set mock mode in application.properties:

# Enable mock mode
brobot.framework.mock=true
# Alternative properties (all synchronized by MockModeManager)
brobot.mock.mode=true
brobot.core.mock-mode=true

Setting State Probabilities

There are two approaches to configure state probabilities:

Configure probabilities directly in state classes:

@State(initial = true)
@Getter
@Slf4j
public class LoginState {

@Autowired(required = false)
private MockStateManagement mockStateManagement;

// Define mock probability for this state
private static final int MOCK_PROBABILITY = 100;

private final StateImage loginButton;

public LoginState() {
loginButton = new StateImage.Builder()
.addPatterns("login-button")
.setName("LoginButton")
.build();
}

@PostConstruct
public void configureMockProbability() {
if (FrameworkSettings.mock && mockStateManagement != null) {
mockStateManagement.setStateProbabilities(MOCK_PROBABILITY, "Login");
log.debug("Configured Login state mock probability to {}%", MOCK_PROBABILITY);
}
}
}

2. Centralized Configuration

Use MockStateManagement to configure multiple states:

@Configuration
@ConditionalOnProperty(name = "brobot.framework.mock", havingValue = "true")
public class MockConfiguration {

@Autowired
private MockStateManagement mockStateManagement;

@PostConstruct
public void configureMockStates() {
// Set initial state probabilities
mockStateManagement.setStateProbabilities(100, "Login"); // Always found
mockStateManagement.setStateProbabilities(0, "Dashboard"); // Initially not found
mockStateManagement.setStateProbabilities(50, "ErrorDialog"); // Sometimes found
}
}

Testing State Transitions

Deterministic Flow Testing

For testing automation flow (like claude-automator), use 100% probabilities to ensure reliable transitions:

@State(initial = true)  // Mark as initial state
public class PromptState {
private static final int MOCK_PROBABILITY = 100; // Always found
// ... state definition
}

@State // Not initial - activated through transition
public class WorkingState {
private static final int MOCK_PROBABILITY = 100; // Always found when active
// ... state definition
}

This ensures:

  • Transitions always succeed when triggered
  • Focus on testing the automation logic, not robustness
  • Predictable test outcomes

Stochastic Testing

For robustness testing, use variable probabilities:

// Simulate unreliable GUI element detection
mockStateManagement.setStateProbabilities(70, "UnstableDialog");

// Test retry logic
for (int i = 0; i < MAX_RETRIES; i++) {
ActionResult result = action.find(dialogElement);
if (result.isSuccess()) break;
Thread.sleep(1000);
}

Dynamic State Simulation

Simulating State Changes

Adjust probabilities during test execution to simulate state transitions:

@Test
public void testLoginFlow() {
// Initial state: Login visible, Dashboard not
mockStateManagement.setStateProbabilities(100, "Login");
mockStateManagement.setStateProbabilities(0, "Dashboard");

// Perform login action
stateNavigator.openState("Dashboard");

// Simulate successful login: Dashboard appears, Login disappears
mockStateManagement.setStateProbabilities(0, "Login");
mockStateManagement.setStateProbabilities(100, "Dashboard");

// Verify transition
assertTrue(stateMemory.getActiveStateNames().contains("Dashboard"));
}

Simulating Temporal Behaviors

public void simulateLoadingSequence() {
// Loading appears
mockStateManagement.setStateProbabilities(100, "LoadingSpinner");

// Simulate loading time
Thread.sleep(2000);

// Loading disappears, content appears
mockStateManagement.setStateProbabilities(0, "LoadingSpinner");
mockStateManagement.setStateProbabilities(100, "ContentLoaded");
}

Best Practices

1. Use 100% Probability for Flow Testing

When testing automation logic (not robustness):

// All states should be reliably findable
private static final int MOCK_PROBABILITY = 100;

2. Set Initial States Appropriately

@State(initial = true)  // Only the starting state(s)
public class InitialState { }

@State // Subsequent states reached through transitions
public class SubsequentState { }

3. Document Mock Behavior

/**
* Login state - always visible at application start.
* Mock probability: 100% (deterministic for flow testing)
*/
@State(initial = true)
public class LoginState { }

4. Separate Mock Configuration

Keep mock-specific configuration separate:

# application.properties
brobot.framework.mock=false # Production

# application-test.properties
brobot.framework.mock=true # Testing

5. Clean State Between Tests

@AfterEach
public void cleanup() {
stateMemory.getActiveStates().clear();
// Reset probabilities if needed
}

Testing Patterns

Pattern 1: Simple Flow Test

@Test
public void testBasicFlow() {
// All states 100% for deterministic testing
mockStateManagement.setStateProbabilities(100, "Start", "Middle", "End");

// Test the flow
assertTrue(stateNavigator.openState("Middle"));
assertTrue(stateNavigator.openState("End"));
}

Pattern 2: Error Recovery Test

@Test
public void testErrorRecovery() {
// Normal states always found
mockStateManagement.setStateProbabilities(100, "Normal");
// Error appears intermittently
mockStateManagement.setStateProbabilities(30, "Error");

// Test should handle both cases
ActionResult result = action.find(element);
if (!result.isSuccess()) {
// Handle error case
handleError();
}
}

Pattern 3: State Verification

@Test
public void verifyStateConfiguration() {
// Verify initial states
var initialStates = stateService.getInitialStates();
assertEquals(1, initialStates.size());
assertEquals("Login", initialStates.get(0).getName());

// Verify all states registered
assertTrue(stateService.getAllStates().stream()
.anyMatch(s -> s.getName().equals("Dashboard")));
}

Debugging Mock Tests

Enable Verbose Logging

logging.level.io.github.jspinak.brobot.tools.testing.mock=DEBUG
logging.level.com.yourapp.states=DEBUG

Log State Transitions

@EventListener
public void handleStateTransition(StateTransitionEvent event) {
log.info("Transition: {} -> {}",
event.getFromState(), event.getToState());
}

Verify Mock Configuration

@Test
public void verifyMockSetup() {
assertTrue(FrameworkSettings.mock, "Mock mode should be enabled");
assertNotNull(mockStateManagement, "MockStateManagement should be available");
}

Common Issues and Solutions

Issue: States Not Being Found

Solution: Verify probability is set > 0:

mockStateManagement.setStateProbabilities(100, "StateName");

Issue: Wrong Initial State

Solution: Ensure only one state has initial = true:

@State(initial = true)  // Only one state should have this

Issue: Transitions Not Working

Solution: Check state registration and transition definitions:

@Transition(from = FromState.class, to = ToState.class)

Issue: Mock Mode Not Activating

Solution: Verify configuration:

brobot.framework.mock=true

Enhanced Mock Infrastructure

Grid Operations Support

Mock mode now provides full support for grid operations without requiring SikuliX:

import io.github.jspinak.brobot.tools.testing.mock.grid.MockGridConfig;

@Test
public void testGridNavigation() {
// Configure grid for testing
MockGridConfig.setDefaultGrid(3, 3); // 3x3 grid

Region screen = new Region(0, 0, 900, 900);

// Test grid navigation
for (int i = 0; i < 9; i++) {
Region gridCell = screen.getGridRegion(i);
assertNotNull(gridCell);
assertEquals(300, gridCell.w());
assertEquals(300, gridCell.h());
}

// Test location to grid mapping
Location centerOfTopRight = new Location(750, 150);
Optional<Integer> gridNum = RegionUtils.getGridNumber(screen, centerOfTopRight);
assertTrue(gridNum.isPresent());
assertEquals(2, gridNum.get()); // Top-right is index 2 in 3x3 grid
}

Scene and Color Analysis Mocking

The MockSceneBuilder provides comprehensive test data for color-based operations:

import io.github.jspinak.brobot.tools.testing.mock.builders.MockSceneBuilder;

@Test
public void testColorMatching() {
// Create mock scene with proper image initialization
Scene scene = MockSceneBuilder.createMockScene();

// Create scene analysis with color profiles
SceneAnalysis analysis = MockSceneBuilder.sceneAnalysis()
.withPixelProfile(0)
.withPixelProfile(1)
.build();

// Color operations work in mock mode
ColorClassifier classifier = new ColorClassifier();
Mat result = classifier.getImageIndices(analysis, ColorCluster.ColorSchemaName.BGR);
assertNotNull(result);
}

Test Base Class - BrobotTestBase

All tests should extend BrobotTestBase for proper mock configuration:

import io.github.jspinak.brobot.test.BrobotTestBase;

public class MyAutomationTest extends BrobotTestBase {

@Test
public void testWithMockMode() {
// Mock mode is automatically enabled
// No headless exceptions
// Fast execution times

ActionResult result = action.find(targetElement);
assertTrue(result.isSuccess());
}
}

Key benefits of BrobotTestBase:

  • Automatic mock mode activation
  • CI/CD pipeline compatibility
  • Fast operation timings (0.01-0.04s)
  • No display server required
  • Consistent test environment

Performance Benefits

Mock mode operations are significantly faster:

OperationMock ModeReal ModeSpeedup
Find operation~0.01s0.5-2s50-200x
Grid calculation~0.01s0.5s50x
Color analysis~0.02s1-2s50-100x
State transition~0.01s0.2-1s20-100x

Common Pitfalls and Solutions

IssueSolution
Tests fail in CI/CDExtend BrobotTestBase
Grid operations return emptyConfigure MockGridConfig.setDefaultGrid()
Color tests throw NPEUse MockSceneBuilder for test data
SikuliX mocking errorsUse real SikuliX objects or Brobot mocks
Inconsistent test resultsEnsure mock mode is enabled in setup

Summary

Mock mode in Brobot enables:

  • Deterministic testing with 100% probabilities for flow validation
  • Stochastic testing with variable probabilities for robustness
  • CI/CD integration without GUI dependencies
  • Rapid development without target application availability
  • Grid operations without SikuliX dependency
  • Color analysis without real images
  • 50-200x faster test execution

Choose probability settings based on your testing goals:

  • 100% for automation flow testing
  • Variable for robustness and error handling
  • Dynamic for simulating complex scenarios

Use the enhanced mock infrastructure for:

  • Grid-based navigation testing
  • Color matching validation
  • Headless environment compatibility
  • Fast CI/CD pipeline execution