We use cookies to enhance your experience on the site
CodeWorlds

Mocking - Simulating Combat Conditions

Master of illusion! Consul Caesar.js needs your help preparing the legion for all possible scenarios without exposing them to real danger. It's time to learn mocking - the art of simulating various conditions and situations in a safe environment!

What Is Mocking in the World of Legionaries?

Mocking is like simulating combat conditions on a training ground. Instead of waiting for a real battle, we simulate it under controlled conditions:

  • Storm simulation instead of waiting for a real one
  • Enemy attack imitation without actual danger
  • Testing systems without affecting real data
  • Checking legion reactions in various scenarios
1// Example - weather service simulation
2const mockWeatherService = {
3 getWeather: jest.fn().mockResolvedValue({
4 condition: 'storm',
5 windSpeed: 45,
6 waveHeight: 4.5,
7 recommendation: 'stay_in_port'
8 })
9};
10
11// Now we can test how our fort reacts to a storm
12// without waiting for real bad weather!

Types of Mock Objects

1. Service Mocks - Specialist Imitation

1// Real weather service
2@Injectable()
3export class WeatherService {
4 async getWeatherReport(coordinates: Coordinates): Promise<WeatherReport> {
5 // Real weather API call
6 const response = await fetch(`https://weather-api.com/marine/${coordinates.lat}/${coordinates.lng}`);
7 return response.json();
8 }
9}
10
11// Mock weather service
12const mockWeatherService = {
13 getWeatherReport: jest.fn().mockImplementation(async (coordinates: Coordinates) => {
14 // Simulate different weather conditions
15 if (coordinates.lat > 60) {
16 return {
17 condition: 'arctic_storm',
18 temperature: -20,
19 windSpeed: 60,
20 visibility: 'zero',
21 recommendation: 'extreme_danger'
22 };
23 }
24
25 if (coordinates.lat < -60) {
26 return {
27 condition: 'antarctic_blizzard',
28 temperature: -40,
29 windSpeed: 80,
30 icebergs: true,
31 recommendation: 'turn_back_immediately'
32 };
33 }
34
35 return {
36 condition: 'calm',
37 temperature: 25,
38 windSpeed: 10,
39 waveHeight: 1.5,
40 recommendation: 'perfect_marching'
41 };
42 })
43};
44
45// Test with mock service
46describe('Navigation Planning', () => {
47 let navigationService: NavigationService;
48
49 beforeEach(() => {
50 navigationService = new NavigationService(mockWeatherService);
51 });
52
53 it('should reject campaign plan in case of arctic storm', async () => {
54 const arcticCoordinates = { lat: 70, lng: -120 };
55
56 const result = await navigationService.planCampaign(arcticCoordinates);
57
58 expect(result.approved).toBe(false);
59 expect(result.reason).toContain('extreme weather conditions');
60 expect(mockWeatherService.getWeatherReport).toHaveBeenCalledWith(arcticCoordinates);
61 });
62
63 it('should approve campaign plan in calm conditions', async () => {
64 const tropicalCoordinates = { lat: 25, lng: -80 };
65
66 const result = await navigationService.planCampaign(tropicalCoordinates);
67
68 expect(result.approved).toBe(true);
69 expect(result.estimatedDuration).toBeGreaterThan(0);
70 });
71});

2. Database Mocks - Treasury Imitation

1// Mock tribute repository
2const mockTributeRepository = {
3 find: jest.fn(),
4 findOne: jest.fn(),
5 save: jest.fn(),
6 delete: jest.fn(),
7 count: jest.fn(),
8
9 // Preset responses for different scenarios
10 mockEmptyVault: function() {
11 this.find.mockResolvedValue([]);
12 this.count.mockResolvedValue(0);
13 },
14
15 mockFullVault: function() {
16 const tributes = [
17 { id: 1, name: 'Golden Coin', value: 100, rarity: 'common' },
18 { id: 2, name: 'Ruby Necklace', value: 1500, rarity: 'rare' },
19 { id: 3, name: 'Diamond Crown', value: 10000, rarity: 'legendary' }
20 ];
21 this.find.mockResolvedValue(tributes);
22 this.count.mockResolvedValue(tributes.length);
23 },
24
25 mockDatabaseError: function() {
26 this.find.mockRejectedValue(new Error('Database connection lost'));
27 this.save.mockRejectedValue(new Error('Transaction failed'));
28 }
29};
30
31describe('Tribute Management', () => {
32 let tributeService: TributeService;
33
34 beforeEach(() => {
35 jest.clearAllMocks();
36 tributeService = new TributeService(mockTributeRepository);
37 });
38
39 it('should handle empty treasury', async () => {
40 mockTributeRepository.mockEmptyVault();
41
42 const tributes = await tributeService.getAllTributes();
43 const summary = await tributeService.getTreasurySummary();
44
45 expect(tributes).toHaveLength(0);
46 expect(summary.totalValue).toBe(0);
47 expect(summary.message).toContain('vault is empty');
48 });
49
50 it('should handle full treasury', async () => {
51 mockTributeRepository.mockFullVault();
52
53 const summary = await tributeService.getTreasurySummary();
54
55 expect(summary.totalValue).toBe(11600);
56 expect(summary.legendaryCount).toBe(1);
57 expect(summary.averageValue).toBe(3866.67);
58 });
59
60 it('should handle database error', async () => {
61 mockTributeRepository.mockDatabaseError();
62
63 await expect(tributeService.getAllTributes())
64 .rejects.toThrow('Database connection lost');
65
66 await expect(tributeService.addTribute({ name: 'Test', value: 100 }))
67 .rejects.toThrow('Transaction failed');
68 });
69});

3. HTTP Service Mocks - Inter-Fort Communication Imitation

1// Mock HttpService for communication with other forts
2const mockHttpService = {
3 get: jest.fn(),
4 post: jest.fn(),
5 put: jest.fn(),
6 delete: jest.fn()
7};
8
9// Setup for different communication scenarios
10class CommunicationMockSetup {
11 static mockSuccessfulCommunication() {
12 mockHttpService.get.mockResolvedValue({
13 data: {
14 cohortName: 'Ultio Reginae',
15 centurion: 'EdDoctus',
16 response: 'Ave! We acknowledge your signal',
17 status: 'friendly'
18 },
19 status: 200
20 });
21 }
22
23 static mockHostileLegion() {
24 mockHttpService.get.mockResolvedValue({
25 data: {
26 cohortName: 'Cohors Interceptor',
27 centurion: 'Legate Crassus',
28 response: 'Stand down or be struck down!',
29 status: 'hostile',
30 warningVolleys: 2
31 },
32 status: 200
33 });
34 }
35
36 static mockNoResponse() {
37 mockHttpService.get.mockRejectedValue(new Error('No response from cohort'));
38 }
39
40 static mockCommunicationJammed() {
41 mockHttpService.get.mockRejectedValue(new Error('Communication channels jammed'));
42 }
43}
44
45describe('Legion Communication', () => {
46 let communicationService: CommunicationService;
47
48 beforeEach(() => {
49 jest.clearAllMocks();
50 communicationService = new CommunicationService(mockHttpService);
51 });
52
53 it('should establish communication with a friendly fort', async () => {
54 CommunicationMockSetup.mockSuccessfulCommunication();
55
56 const result = await communicationService.contactLegion({
57 coordinates: { lat: 25.7, lng: -80.1 },
58 frequency: '156.800'
59 });
60
61 expect(result.status).toBe('successful');
62 expect(result.cohortStatus).toBe('friendly');
63 expect(result.recommendation).toBe('safe_to_approach');
64 });
65
66 it('should detect hostile intentions', async () => {
67 CommunicationMockSetup.mockHostileLegion();
68
69 const result = await communicationService.contactLegion({
70 coordinates: { lat: 30.0, lng: -85.0 },
71 frequency: '156.800'
72 });
73
74 expect(result.status).toBe('successful');
75 expect(result.cohortStatus).toBe('hostile');
76 expect(result.recommendation).toBe('maintain_distance');
77 expect(result.threatLevel).toBe('high');
78 });
79
80 it('should handle no response', async () => {
81 CommunicationMockSetup.mockNoResponse();
82
83 const result = await communicationService.contactLegion({
84 coordinates: { lat: 0, lng: 0 },
85 frequency: '156.800'
86 });
87
88 expect(result.status).toBe('failed');
89 expect(result.reason).toContain('No response');
90 expect(result.recommendation).toBe('proceed_with_caution');
91 });
92});

4. Time Mocks - Time Control

1// Mock Date and timers for time-based tests
2describe('Expedition Timing', () => {
3 let expeditionService: ExpeditionService;
4
5 beforeEach(() => {
6 // Mock time to a fixed moment
7 jest.useFakeTimers();
8 jest.setSystemTime(new Date('2023-06-15T08:00:00Z'));
9
10 expeditionService = new ExpeditionService();
11 });
12
13 afterEach(() => {
14 jest.useRealTimers();
15 });
16
17 it('should schedule expedition for the right time', async () => {
18 const expeditionPlan = {
19 departureTime: new Date('2023-06-15T10:00:00Z'),
20 duration: 7 * 24 * 60 * 60 * 1000, // 7 days in ms
21 destination: 'Tribute Island'
22 };
23
24 const result = await expeditionService.scheduleExpedition(expeditionPlan);
25
26 expect(result.departureTime).toEqual(new Date('2023-06-15T10:00:00Z'));
27 expect(result.expectedReturn).toEqual(new Date('2023-06-22T10:00:00Z'));
28 expect(result.preparationTime).toBe(2 * 60 * 60 * 1000); // 2 hours for preparation
29 });
30
31 it('should handle expedition time exceeded', async () => {
32 // Start expedition
33 const expedition = await expeditionService.startExpedition({
34 id: 'test-expedition',
35 duration: 60 * 60 * 1000 // 1 hour
36 });
37
38 expect(expedition.status).toBe('in_progress');
39
40 // Advance time by 2 hours
41 jest.advanceTimersByTime(2 * 60 * 60 * 1000);
42
43 // Check expedition status
44 const status = await expeditionService.checkExpeditionStatus('test-expedition');
45
46 expect(status.isOverdue).toBe(true);
47 expect(status.overdueBy).toBe(60 * 60 * 1000); // 1 hour late
48 expect(status.recommendation).toBe('send_rescue_mission');
49 });
50});

5. Complex Scenario Mocks

1// Mock manager for complex scenarios
2class BattleScenarioMocks {
3 static setupEpicFieldBattle() {
4 const mockEnemyLegion = {
5 cohorts: [
6 { name: 'Cohors Victrix', ballistae: 40, health: 100, position: { x: 100, y: 200 } },
7 { name: 'Cohors Defiant', ballistae: 32, health: 90, position: { x: 150, y: 180 } },
8 { name: 'Cohors Vindicta', ballistae: 28, health: 85, position: { x: 80, y: 220 } }
9 ],
10 formation: 'line_of_battle',
11 commander: 'Legate Scipio',
12 morale: 'high'
13 };
14
15 const mockWeatherConditions = {
16 visibility: 'poor',
17 windDirection: 'northwest',
18 windSpeed: 25,
19 waveHeight: 3.0,
20 timeOfDay: 'dawn'
21 };
22
23 const mockBattleEvents = [
24 { time: 0, event: 'battle_begins', description: 'Enemy legion spotted on horizon' },
25 { time: 300, event: 'first_volley', result: 'enemy_hit', damage: 15 },
26 { time: 600, event: 'return_fire', result: 'friendly_hit', damage: 20 },
27 { time: 900, event: 'weather_change', change: 'fog_rolls_in' },
28 { time: 1200, event: 'critical_hit', target: 'enemy_praetoria', damage: 40 },
29 { time: 1500, event: 'enemy_retreat', reason: 'heavy_casualties' }
30 ];
31
32 return {
33 enemyLegion: mockEnemyLegion,
34 weather: mockWeatherConditions,
35 events: mockBattleEvents
36 };
37 }
38}
39
40describe('Epic Field Battle', () => {
41 let battleService: BattleService;
42 let mockEventSystem: jest.Mocked<EventSystem>;
43
44 beforeEach(() => {
45 mockEventSystem = {
46 emit: jest.fn(),
47 on: jest.fn(),
48 removeListener: jest.fn()
49 };
50
51 battleService = new BattleService(mockEventSystem);
52 });
53
54 it('should conduct an epic field battle', async () => {
55 const scenario = BattleScenarioMocks.setupEpicFieldBattle();
56
57 // Mock responses for different battle phases
58 mockEventSystem.emit
59 .mockReturnValueOnce(true) // battle_begins
60 .mockReturnValueOnce(true) // first_volley
61 .mockReturnValueOnce(true) // return_fire
62 .mockReturnValueOnce(true) // weather_change
63 .mockReturnValueOnce(true) // critical_hit
64 .mockReturnValueOnce(true); // enemy_retreat
65
66 const result = await battleService.simulateBattle({
67 playerLegion: {
68 cohorts: [{ name: 'Cohors Nigra', ballistae: 32, health: 100 }],
69 commander: 'Centurion Caesar'
70 },
71 enemyLegion: scenario.enemyLegion,
72 weather: scenario.weather,
73 events: scenario.events
74 });
75
76 // Check battle results
77 expect(result.outcome).toBe('victory');
78 expect(result.playerLosses).toBeLessThan(50);
79 expect(result.enemyLosses).toBeGreaterThan(70);
80 expect(result.battleDuration).toBe(1500); // 25 minutes
81 expect(result.decisiveEvent).toBe('critical_hit');
82
83 // Check that events were called in the right order
84 expect(mockEventSystem.emit).toHaveBeenCalledTimes(6);
85 expect(mockEventSystem.emit).toHaveBeenNthCalledWith(
86 1, 'battle_event', expect.objectContaining({ event: 'battle_begins' })
87 );
88 expect(mockEventSystem.emit).toHaveBeenLastCalledWith(
89 'battle_event', expect.objectContaining({ event: 'enemy_retreat' })
90 );
91 });
92});

6. Mock Factories

1// Factory for creating mock objects
2class LegionaryMockFactory {
3 static createMockLegionary(overrides: Partial<Legionary> = {}): Legionary {
4 return {
5 id: Math.random().toString(36),
6 name: 'Test Legionary',
7 rank: 'Legionary',
8 experience: 100,
9 skills: ['Marching', 'Combat'],
10 health: 100,
11 morale: 80,
12 equipment: ['Gladius', 'Pilum'],
13 ...overrides
14 };
15 }
16
17 static createMockLegion(size: number, ranks: string[] = []): Legionary[] {
18 return Array.from({ length: size }, (_, index) => {
19 const rank = ranks[index] || (index === 0 ? 'Centurion' : 'Legionary');
20 return this.createMockLegionary({
21 name: `Legionary ${index + 1}`,
22 rank,
23 experience: 50 + (index * 25)
24 });
25 });
26 }
27
28 static createMockLegion(legionSize: number = 20): Legion {
29 return {
30 id: Math.random().toString(36),
31 name: 'Test Legion',
32 type: 'Cohors',
33 health: 100,
34 ballistae: 24,
35 speed: 12,
36 capacity: 50,
37 legion: this.createMockLegion(legionSize),
38 supplies: {
39 food: 30,
40 water: 25,
41 ammunition: 500,
42 wine: 100
43 }
44 };
45 }
46}
47
48// Using the mock factory
49describe('Legion Operations', () => {
50 it('should manage a legion of different cohorts', () => {
51 const legate = LegionaryMockFactory.createMockLegionary({
52 name: 'Legate Caesar',
53 rank: 'Legate',
54 experience: 2000
55 });
56
57 const legion = [
58 LegionaryMockFactory.createMockLegion(30), // Large praetorian cohort
59 LegionaryMockFactory.createMockLegion(20), // Medium cohort
60 LegionaryMockFactory.createMockLegion(15), // Small scout cohort
61 ];
62
63 const legionManager = new LegionManager(legate, legion);
64
65 expect(legionManager.getTotalFirepower()).toBeGreaterThan(60);
66 expect(legionManager.getTotalLegion()).toBe(65);
67 expect(legionManager.isReadyForExpedition()).toBe(true);
68 });
69});

Mocking Best Practices

1. Mock Cleanup

1describe('Service Tests', () => {
2 afterEach(() => {
3 jest.clearAllMocks(); // Clear all mock calls
4 jest.restoreAllMocks(); // Restore original implementations
5 });
6});

2. Realistic Mock Data

1// ✅ Good mock - realistic data
2const goodMockWeather = {
3 temperature: 23,
4 windSpeed: 15,
5 waveHeight: 2.1,
6 visibility: 'good',
7 humidity: 78
8};
9
10// ❌ Bad mock - unrealistic data
11const badMockWeather = {
12 temperature: 999,
13 windSpeed: -50,
14 waveHeight: 'very big',
15 visibility: true
16};

3. Verify Mock Interactions

1it('should call weather service with correct parameters', async () => {
2 await navigationService.planRoute(startPoint, endPoint);
3
4 expect(mockWeatherService.getWeather).toHaveBeenCalledTimes(2);
5 expect(mockWeatherService.getWeather).toHaveBeenNthCalledWith(1, startPoint);
6 expect(mockWeatherService.getWeather).toHaveBeenNthCalledWith(2, endPoint);
7});

Mocking is the art of preparing the legion for all possible scenarios without exposing it to real danger. Well-prepared mocks allow you to test even the most extreme weather in a safe environment!

Go to CodeWorlds