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

Mock Mode vs Headless Modeโ€‹

Important Distinction:

  • Mock Mode (brobot.mock): Simulates actions and pattern matching for testing without real screen interaction
  • Headless Mode (brobot.headless): Indicates no display is available (e.g., server environments, CI/CD)

These are independent settings:

  • You can run mock mode with a display (development testing)
  • You can run mock mode without a display (CI/CD testing)
  • Headless environments typically use mock mode, but mock mode doesn't require headless

Core Conceptsโ€‹

What Mock Mode Doesโ€‹

When mock mode is enabled (via brobot.mock=true or brobot.core.mock=true property, or programmatically with MockModeManager.setMockMode(true)):

  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 uses simplified mock configuration properties:

# application.properties
# Enable mock mode (simulated actions)
brobot.mock=true

# Probability of action success (0.0 to 1.0, default 1.0)
brobot.mock.action.success.probability=0.95

# Headless configuration (if no display available)
brobot.headless=false # Set to true for CI/CD environments
brobot.headless.debug=false # Enable for headless detection debugging

Note: The brobot.headless property must be explicitly set. Auto-detection has been removed due to reliability issues on Windows systems.

Property System Clarification: Brobot supports two property forms for mock mode:

  • brobot.mock=true - Simplified system property (managed by MockModeManager)
  • brobot.core.mock=true - Spring Boot configuration property (mapped to BrobotProperties)

Both forms are valid and synchronized automatically. Use whichever fits your configuration style.

Programmatic Configurationโ€‹

// Note: BrobotProperties must be injected as a dependency
@Autowired
private BrobotProperties brobotProperties;

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

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

// Check if mock mode is enabled
if (brobotProperties.getCore().isMock()) {
// Mock-specific logic
}

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

The MockModeManager automatically synchronizes mock mode across:

  • System properties (brobot.mock)
  • ExecutionEnvironment (for runtime behavior)
  • brobotProperties.getCore().isMock() (for compatibility)

Action Success Probabilityโ€‹

The brobot.mock.action.success.probability property controls how often simulated actions succeed:

  • 1.0 (default): All actions always succeed - ideal for deterministic testing
  • 0.95: 95% success rate - simulates realistic conditions
  • 0.5: 50% success rate - stress testing
  • 0.0: All actions always fail - failure path testing

This applies to actions like click, type, and drag. Find operations still require ActionSnapshots for proper match simulation.

Setting State Probabilitiesโ€‹

There are two approaches to configure state probabilities:

Configure probabilities directly in state classes:

package com.yourapp.states;

import io.github.jspinak.brobot.annotations.State;
import io.github.jspinak.brobot.config.core.BrobotProperties;
import io.github.jspinak.brobot.datastructures.state.stateobject.StateImage;
import io.github.jspinak.brobot.tools.testing.mock.state.MockStateManagement;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

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

@Autowired(required = false)
private MockStateManagement mockStateManagement;

@Autowired
private BrobotProperties brobotProperties;

// 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 (brobotProperties.getCore().isMock() && 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.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.core.mock=false # Production

# application-test.properties
brobot.core.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โ€‹

@Autowired
private InitialStates initialStates;

@Autowired
private StateService stateService;

@Test
public void verifyStateConfiguration() {
// Verify initial states are registered
assertTrue(initialStates.hasRegisteredInitialStates());
var initialStateNames = initialStates.getRegisteredInitialStates();
assertEquals(1, initialStateNames.size());
assertEquals("Login", initialStateNames.get(0));

// 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(brobotProperties.getCore().isMock(), "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. Use the correct transition format:

@TransitionSet(state = SourceState.class)  // Source state for these transitions
@Component
@RequiredArgsConstructor
public class SourceStateTransitions {

private final SourceState sourceState;
private final Action action;
private final BrobotProperties brobotProperties;

/**
* Navigate FROM SourceState TO TargetState
*/
@OutgoingTransition(activate = {TargetState.class}, pathCost = 1)
public boolean toTargetState() {
if (brobotProperties.getCore().isMock()) return true;
return action.click(sourceState.getButton()).isSuccess();
}

/**
* Verify arrival AT SourceState
*/
@IncomingTransition
public boolean verifyArrival() {
if (brobotProperties.getCore().isMock()) return true;
return action.find(sourceState.getElement()).isSuccess();
}
}

Issue: Mock Mode Not Activatingโ€‹

Solution: Verify configuration:

brobot.core.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

See Alsoโ€‹

Essential Testing Documentationโ€‹

Mock Mode Ecosystemโ€‹

State and Transition Documentationโ€‹

Configurationโ€‹

Tutorialsโ€‹