5 KiB
5 KiB
Testing Utilities
The Process package provides comprehensive testing utilities for process-dependent code.
Process Faking
Basic Faking
final factory = Factory();
// Fake specific commands
factory.fake({
'ls': 'file1.txt\nfile2.txt',
'cat file1.txt': 'Hello, World!',
'grep pattern': (process) => 'Matched line',
});
// Run fake processes
final result = await factory.command('ls').run();
expect(result.output().trim(), equals('file1.txt\nfile2.txt'));
Preventing Real Processes
// Prevent any real process execution
factory.fake().preventStrayProcesses();
// This will throw an exception
await factory.command('real-command').run();
Dynamic Results
factory.fake({
'random': (process) =>
DateTime.now().millisecondsSinceEpoch.toString(),
'conditional': (process) =>
process.env['SUCCESS'] == 'true' ? 'success' : 'failure',
});
Process Descriptions
Basic Description
final description = FakeProcessDescription()
..withExitCode(0)
..replaceOutput('Test output')
..replaceErrorOutput('Test error');
factory.fake({
'test-command': description,
});
Simulating Long-Running Processes
final description = FakeProcessDescription()
..withOutputSequence(['Step 1', 'Step 2', 'Step 3'])
..withDelay(Duration(milliseconds: 100))
..runsFor(duration: Duration(seconds: 1));
factory.fake({
'long-task': description,
});
Simulating Process Failures
final description = FakeProcessDescription()
..withExitCode(1)
..replaceOutput('Operation failed')
..replaceErrorOutput('Error: Invalid input');
factory.fake({
'failing-task': description,
});
Process Sequences
Basic Sequences
final sequence = FakeProcessSequence()
..then(FakeProcessResult(output: 'First'))
..then(FakeProcessResult(output: 'Second'))
..then(FakeProcessResult(output: 'Third'));
factory.fake({
'sequential-task': sequence,
});
Alternating Success/Failure
final sequence = FakeProcessSequence.alternating(3);
while (sequence.hasMore) {
final result = sequence.call() as FakeProcessResult;
print('Success: ${result.successful()}');
}
Custom Sequences
final sequence = FakeProcessSequence.fromOutputs([
'Starting...',
'Processing...',
'Complete!',
]);
factory.fake({
'progress-task': sequence,
});
Testing Process Pools
test('executes processes concurrently', () async {
factory.fake({
'task1': FakeProcessDescription()
..withDelay(Duration(seconds: 1))
..replaceOutput('Result 1'),
'task2': FakeProcessDescription()
..withDelay(Duration(seconds: 1))
..replaceOutput('Result 2'),
});
final results = await factory.pool((pool) {
pool.command('task1');
pool.command('task2');
}).start();
expect(results.successful(), isTrue);
expect(results.total, equals(2));
});
Testing Process Pipes
test('pipes output between processes', () async {
factory.fake({
'generate': 'initial data',
'transform': (process) => process.input.toUpperCase(),
'filter': (process) => process.input.contains('DATA') ? process.input : '',
});
final result = await factory.pipeThrough((pipe) {
pipe.command('generate');
pipe.command('transform');
pipe.command('filter');
}).run();
expect(result.output(), equals('INITIAL DATA'));
});
Best Practices
- Use
preventStrayProcesses()
in tests to catch unintended process execution - Simulate realistic scenarios with delays and sequences
- Test both success and failure cases
- Test process configuration (environment, working directory, etc.)
- Test process coordination (pools and pipes)
- Use process descriptions for complex behaviors
- Test timeout and error handling
- Mock system-specific behaviors
- Clean up resources in tests
- Test real-time output handling
Example Test Suite
void main() {
group('Process Manager', () {
late Factory factory;
setUp(() {
factory = Factory();
factory.fake().preventStrayProcesses();
});
test('handles successful process', () async {
factory.fake({
'successful-task': FakeProcessDescription()
..withExitCode(0)
..replaceOutput('Success!'),
});
final result = await factory
.command('successful-task')
.run();
expect(result.successful(), isTrue);
expect(result.output(), equals('Success!'));
});
test('handles process failure', () async {
factory.fake({
'failing-task': FakeProcessDescription()
..withExitCode(1)
..replaceErrorOutput('Failed!'),
});
final result = await factory
.command('failing-task')
.run();
expect(result.failed(), isTrue);
expect(result.errorOutput(), equals('Failed!'));
});
});
}
For more information, see:
- Process Execution for basic process management
- Process Coordination for pools and pipes