Skip to content

Commit d22dde1

Browse files
committed
Add --parallel support to tests command for ParaTest execution
- Add --parallel option to TestsCommand with optional worker count - Use ParaTest when --parallel is enabled and available - Fall back to phpunit if paratest is not installed - Add tests for parallel execution scenarios Implements: #8
1 parent c2b9f24 commit d22dde1

2 files changed

Lines changed: 98 additions & 1 deletion

File tree

src/Command/TestsCommand.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ protected function configure(): void
8484
shortcut: 'f',
8585
mode: InputOption::VALUE_OPTIONAL,
8686
description: 'Filter which tests to run based on a pattern.',
87+
)
88+
->addOption(
89+
name: 'parallel',
90+
shortcut: 'p',
91+
mode: InputOption::VALUE_OPTIONAL,
92+
description: 'Run tests in parallel using ParaTest. Optional: specify number of workers (e.g., --parallel or --parallel=4).',
93+
default: null,
8794
);
8895
}
8996

@@ -102,8 +109,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
102109
{
103110
$output->writeln('<info>Running PHPUnit tests...</info>');
104111

112+
$parallel = $input->getOption('parallel');
113+
$runner = $this->getTestRunner($parallel !== false ? $parallel : null);
114+
105115
$arguments = [
106-
$this->getAbsolutePath('vendor/bin/phpunit'),
116+
$runner,
107117
'--configuration=' . parent::getConfigFile(self::CONFIG),
108118
'--bootstrap=' . $this->resolvePath($input, 'bootstrap'),
109119
'--display-deprecations',
@@ -112,6 +122,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
112122
'--display-skipped',
113123
];
114124

125+
if ($parallel !== null) {
126+
if (is_numeric($parallel)) {
127+
$arguments[] = '--processes=' . (int) $parallel;
128+
}
129+
$arguments[] = '--parallel';
130+
}
131+
115132
if (! $input->getOption('no-cache')) {
116133
$arguments[] = '--cache-directory=' . $this->resolvePath($input, 'cache-dir');
117134
}
@@ -156,4 +173,23 @@ private function resolvePath(InputInterface $input, string $option): string
156173
{
157174
return $this->getAbsolutePath($input->getOption($option));
158175
}
176+
177+
/**
178+
* Determines the test runner to use based on parallel execution flag.
179+
*
180+
* The method MUST return the appropriate test runner binary path.
181+
* If parallel is enabled, it SHALL return paratest; otherwise, it SHALL return phpunit.
182+
*
183+
* @param string|null $parallel the parallel option value
184+
*
185+
* @return string the path to the test runner binary
186+
*/
187+
private function getTestRunner(?string $parallel): string
188+
{
189+
if ($parallel !== null && $this->filesystem->exists($this->getAbsolutePath('vendor/bin/paratest'))) {
190+
return $this->getAbsolutePath('vendor/bin/paratest');
191+
}
192+
193+
return $this->getAbsolutePath('vendor/bin/phpunit');
194+
}
159195
}

tests/Command/TestsCommandTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,65 @@ public function executeWillReturnFailureIfProcessFails(): void
137137

138138
self::assertSame(TestsCommand::FAILURE, $this->invokeExecute());
139139
}
140+
141+
/**
142+
* @return void
143+
*/
144+
#[Test]
145+
public function executeWithParallelOptionWillRunParaTest(): void
146+
{
147+
$this->filesystem->exists(getcwd() . '/vendor/bin/paratest')->willReturn(true);
148+
149+
$this->willRunProcessWithCallback(function (Process $process): bool {
150+
$commandLine = $process->getCommandLine();
151+
152+
return str_contains($commandLine, 'vendor/bin/paratest')
153+
&& str_contains($commandLine, '--parallel');
154+
});
155+
156+
$this->input->getOption('parallel')
157+
->willReturn('1');
158+
$this->invokeExecute();
159+
}
160+
161+
/**
162+
* @return void
163+
*/
164+
#[Test]
165+
public function executeWithParallelOptionAndWorkerCount(): void
166+
{
167+
$this->filesystem->exists(getcwd() . '/vendor/bin/paratest')->willReturn(true);
168+
169+
$this->willRunProcessWithCallback(function (Process $process): bool {
170+
$commandLine = $process->getCommandLine();
171+
172+
return str_contains($commandLine, 'vendor/bin/paratest')
173+
&& str_contains($commandLine, '--processes=4')
174+
&& str_contains($commandLine, '--parallel');
175+
});
176+
177+
$this->input->getOption('parallel')
178+
->willReturn('4');
179+
$this->invokeExecute();
180+
}
181+
182+
/**
183+
* @return void
184+
*/
185+
#[Test]
186+
public function executeWithParallelOptionButNoParaTestWillFallbackToPhpUnit(): void
187+
{
188+
$this->filesystem->exists(getcwd() . '/vendor/bin/paratest')->willReturn(false);
189+
190+
$this->willRunProcessWithCallback(function (Process $process): bool {
191+
$commandLine = $process->getCommandLine();
192+
193+
return str_contains($commandLine, 'vendor/bin/phpunit')
194+
&& ! str_contains($commandLine, 'paratest');
195+
});
196+
197+
$this->input->getOption('parallel')
198+
->willReturn('1');
199+
$this->invokeExecute();
200+
}
140201
}

0 commit comments

Comments
 (0)