Skip to content

Commit 0312cb5

Browse files
committed
Factorize mocking code in tests
1 parent 4fe0ce2 commit 0312cb5

File tree

1 file changed

+119
-83
lines changed

1 file changed

+119
-83
lines changed

integration/vscode/ada/test/e3-testsuite/e3_testsuite.test.ts

Lines changed: 119 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,119 @@
1-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
21
import assert from 'assert';
32
import { EOL } from 'os';
43
import path from 'path';
54
import { anything, instance, mock, reset, spy, when } from 'ts-mockito';
6-
import { TestItem, TestItemCollection, TestMessage, TestRun, Uri, workspace } from 'vscode';
5+
import {
6+
TestController,
7+
TestItem,
8+
TestItemCollection,
9+
TestMessage,
10+
TestRun,
11+
Uri,
12+
workspace,
13+
} from 'vscode';
714
import { CancellationTokenSource } from 'vscode-languageclient';
815
import * as e3 from '../../src/e3Testsuite';
916
import { activate } from '../utils';
1017

18+
/**
19+
* Interface for capturing test execution results
20+
*/
21+
interface TestResults {
22+
enqueued: string[];
23+
started: string[];
24+
passed: string[];
25+
failed: { id: string; message: TestMessage[] }[];
26+
errors: { id: string; message: TestMessage[] }[];
27+
}
28+
29+
/**
30+
* Class for managing mocking setup with mutable state
31+
*/
32+
class MockSetup {
33+
public spyCtrl: TestController;
34+
public mockRun: TestRun;
35+
public consoleOutput: string = '';
36+
public results?: TestResults;
37+
38+
constructor(mode: 'basic' | 'full' = 'basic') {
39+
this.spyCtrl = spy(e3.controller);
40+
const mockRun = mock<TestRun>();
41+
42+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
43+
44+
// Console output capture (common to both modes)
45+
when(mockRun.appendOutput(anything())).thenCall((output: string) => {
46+
this.consoleOutput += output.replace(/(\r+\n|\n\r+)/g, '\n');
47+
});
48+
49+
// Set up test result capture for full mode
50+
if (mode === 'full') {
51+
const enqueued: string[] = [];
52+
const started: string[] = [];
53+
const passed: string[] = [];
54+
const failed: { id: string; message: TestMessage[] }[] = [];
55+
const errors: { id: string; message: TestMessage[] }[] = [];
56+
57+
when(mockRun.enqueued(anything())).thenCall((item: TestItem) => {
58+
enqueued.push(item.id);
59+
});
60+
when(mockRun.started(anything())).thenCall((item: TestItem) => {
61+
started.push(item.id);
62+
});
63+
when(mockRun.passed(anything())).thenCall((item: TestItem) => {
64+
passed.push(item.id);
65+
});
66+
when(mockRun.failed(anything(), anything())).thenCall(
67+
(item: TestItem, message?: TestMessage | TestMessage[]) => {
68+
let messages: TestMessage[] = [];
69+
if (Array.isArray(message)) {
70+
messages = message;
71+
} else if (message) {
72+
messages = [message];
73+
}
74+
failed.push({ id: item.id, message: messages });
75+
},
76+
);
77+
when(mockRun.errored(anything(), anything())).thenCall(
78+
(item: TestItem, message?: TestMessage | TestMessage[]) => {
79+
let messages: TestMessage[] = [];
80+
if (Array.isArray(message)) {
81+
messages = message;
82+
} else if (message) {
83+
messages = [message];
84+
}
85+
errors.push({ id: item.id, message: messages });
86+
},
87+
);
88+
89+
this.results = {
90+
enqueued,
91+
started,
92+
passed,
93+
failed,
94+
errors,
95+
};
96+
}
97+
98+
// Create the mock run instance and set up spy controller mappings
99+
this.mockRun = instance(mockRun);
100+
when(this.spyCtrl.createTestRun(anything())).thenReturn(this.mockRun);
101+
when(this.spyCtrl.createTestRun(anything(), anything())).thenReturn(this.mockRun);
102+
when(this.spyCtrl.createTestRun(anything(), anything(), anything())).thenReturn(
103+
this.mockRun,
104+
);
105+
106+
/* eslint-enable @typescript-eslint/no-unsafe-argument */
107+
}
108+
109+
/**
110+
* Cleans up mocking after test execution
111+
*/
112+
cleanup(): void {
113+
reset(this.spyCtrl);
114+
}
115+
}
116+
11117
suite('e3-testsuite', function () {
12118
this.beforeAll(async function () {
13119
await activate();
@@ -64,20 +170,8 @@ suite('e3-testsuite', function () {
64170
test('Test list after run', async function () {
65171
await e3.controller.refreshHandler!(new CancellationTokenSource().token);
66172

67-
const spyCtrl = spy(e3.controller);
173+
const mockSetup = new MockSetup('basic');
68174
try {
69-
const mockRun = mock<TestRun>();
70-
let consoleOutput = '';
71-
when(mockRun.appendOutput(anything())).thenCall((output: string) => {
72-
consoleOutput += output.replace(/(\r+\n|\n\r+)/g, '\n');
73-
});
74-
75-
const run = instance(mockRun);
76-
77-
when(spyCtrl.createTestRun(anything())).thenReturn(run);
78-
when(spyCtrl.createTestRun(anything(), anything())).thenReturn(run);
79-
when(spyCtrl.createTestRun(anything(), anything(), anything())).thenReturn(run);
80-
81175
await e3.runHandler(
82176
{ include: undefined, exclude: undefined, profile: undefined },
83177
new CancellationTokenSource().token,
@@ -211,75 +305,28 @@ suite('e3-testsuite', function () {
211305
// Include console output in the error message for debugging
212306
const errorMessage =
213307
`Test structure assertion failed.\n\n` +
214-
`Console output:\n${consoleOutput}\n\n` +
308+
`Console output:\n${mockSetup.consoleOutput}\n\n` +
215309
`Original error:\n${String(error)}`;
216310
throw new Error(errorMessage);
217311
}
218312
} finally {
219-
reset(spyCtrl);
313+
mockSetup.cleanup();
220314
}
221315
});
222316

223317
test('Capturing test results', async function () {
224318
await e3.controller.refreshHandler!(new CancellationTokenSource().token);
225319

226-
const spyCtrl = spy(e3.controller);
320+
const mockSetup = new MockSetup('full');
227321
try {
228-
const mockRun = mock<TestRun>();
229-
let consoleOutput = '';
230-
when(mockRun.appendOutput(anything())).thenCall((output: string) => {
231-
consoleOutput += output.replace(/(\r+\n|\n\r+)/g, '\n');
232-
});
233-
234-
const enqueued: string[] = [];
235-
const started: string[] = [];
236-
const passed: string[] = [];
237-
const failed: { id: string; message: TestMessage[] }[] = [];
238-
const errors: { id: string; message: TestMessage[] }[] = [];
239-
240-
when(mockRun.enqueued(anything())).thenCall((item: TestItem) => {
241-
enqueued.push(item.id);
242-
});
243-
when(mockRun.started(anything())).thenCall((item: TestItem) => {
244-
started.push(item.id);
245-
});
246-
when(mockRun.passed(anything())).thenCall((item: TestItem) => {
247-
passed.push(item.id);
248-
});
249-
when(mockRun.failed(anything(), anything())).thenCall(
250-
(item: TestItem, message?: TestMessage | TestMessage[]) => {
251-
let messages: TestMessage[] = [];
252-
if (Array.isArray(message)) {
253-
messages = message;
254-
} else if (message) {
255-
messages = [message];
256-
}
257-
failed.push({ id: item.id, message: messages });
258-
},
259-
);
260-
when(mockRun.errored(anything(), anything())).thenCall(
261-
(item: TestItem, message?: TestMessage | TestMessage[]) => {
262-
let messages: TestMessage[] = [];
263-
if (Array.isArray(message)) {
264-
messages = message;
265-
} else if (message) {
266-
messages = [message];
267-
}
268-
errors.push({ id: item.id, message: messages });
269-
},
270-
);
271-
272-
const run = instance(mockRun);
273-
274-
when(spyCtrl.createTestRun(anything())).thenReturn(run);
275-
when(spyCtrl.createTestRun(anything(), anything())).thenReturn(run);
276-
when(spyCtrl.createTestRun(anything(), anything(), anything())).thenReturn(run);
277-
278322
await e3.runHandler(
279323
{ include: undefined, exclude: undefined, profile: undefined },
280324
new CancellationTokenSource().token,
281325
);
282326

327+
const consoleOutput = mockSetup.consoleOutput;
328+
const { enqueued, started, passed, failed, errors } = mockSetup.results!;
329+
283330
const workspaceRoot = workspace.workspaceFolders![0].uri.fsPath;
284331
const testsuitePath = `${workspaceRoot}${path.sep}testsuite.py`;
285332
const pythonPathRegex =
@@ -405,7 +452,7 @@ suite('e3-testsuite', function () {
405452
]);
406453
assert.deepStrictEqual(errors, []);
407454
} finally {
408-
reset(spyCtrl);
455+
mockSetup.cleanup();
409456
}
410457
});
411458

@@ -421,26 +468,15 @@ suite('e3-testsuite', function () {
421468
const testArgs = ['--verbose', '--show-time-info'];
422469
await config.update('args', testArgs, false);
423470

424-
const spyCtrl = spy(e3.controller);
471+
const mockSetup = new MockSetup('basic');
425472
try {
426-
const mockRun = mock<TestRun>();
427-
let consoleOutput = '';
428-
when(mockRun.appendOutput(anything())).thenCall((output: string) => {
429-
consoleOutput += output.replace(/(\r+\n|\n\r+)/g, '\n');
430-
});
431-
432-
const run = instance(mockRun);
433-
434-
when(spyCtrl.createTestRun(anything())).thenReturn(run);
435-
when(spyCtrl.createTestRun(anything(), anything())).thenReturn(run);
436-
when(spyCtrl.createTestRun(anything(), anything(), anything())).thenReturn(run);
437-
438473
// Run the handler
439474
await e3.runHandler(
440475
{ include: undefined, exclude: undefined, profile: undefined },
441476
new CancellationTokenSource().token,
442477
);
443478

479+
const consoleOutput = mockSetup.consoleOutput;
444480
// Check that the custom args appear in the console output
445481
assert.ok(
446482
consoleOutput.includes('--verbose'),
@@ -471,7 +507,7 @@ suite('e3-testsuite', function () {
471507
`Expected '--show-time-info' not found in command: ${commandLine}`,
472508
);
473509
} finally {
474-
reset(spyCtrl);
510+
mockSetup.cleanup();
475511
}
476512
} finally {
477513
// Always restore original configuration

0 commit comments

Comments
 (0)