Comments (9)
I have to look into the code but as far as I recall the skipping logic follows the timeout logic. Let me get back after reconfirming.
from infection.
PR that added this feature: #1171
Another relevant PR: #1424
from infection.
It looks like we are tracking full test time instead of timings for individual tests, at line 106 here:
So this isn't a problem with the feature itself, but rather a problem with the underlying data aggregation.
from infection.
At this moment I don't feel particularly good about investing time into fixing the issue: the timeout feature exists to limit the time Infection spends running tests, so there should be no harm in adjusting (bumping) the timeout when needed to run more tests. But I can see it can be frustrating.
Furthermore, I still agree with my recommendation from this comment to tag integration tests with @coversNothing
.
from infection.
Personally I have to agree with @danepowell, I find the current behaviour quite unintuitive.
If I configure a timeout for a test (regardless of the framework/language), I personally would expect it to configure it for the execution of a singular test (unless the config hints at something else of course).
But personal bias aside, we're not in any language or any framework, we're in PHP and arguably the de facto test framework is PHPUnit. And in this case still, this is how the timeout works:
`CounterTest.php`
<?php
declare(strict_types=1);
namespace App\Tests;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\TestCase;
use function range;
use function sleep;
#[Small]
final class CounterTest extends TestCase
{
#[DataProvider('inputProvider')]
public function test_smaller_than_small(mixed $input): void
{
$this->addToAssertionCount(1);
}
#[DataProvider('inputProvider')]
public function test_bigger_than_small(mixed $input): void
{
sleep(2);
$this->addToAssertionCount(1);
}
public static function inputProvider(): iterable
{
foreach (range(1, 10) as $i) {
yield [$i];
}
}
}
Provided your enforce the timeout with enforceTimeLimit="true"
in your PHPUnit configuration file or --enforce-time-limit
, only the individual tests will timeout. Indeed, although the timeout PHPUnit is somewhat inflexible*, it is the execution time of the individual test that is compared to the timeout.
*: There is no Timeout
attribute, so besides the hardcoded Small
, Medium
and Large
the only recourse you have is the default timeout time. And the timeouts are configured at the test case level, not the test level.
I think the current timeout is not devoid or sense or use, but it is not what I would expect timeout
to be. Maybe something like subjectOverallTimeout
or something would be more appropriate, definitely not the best name, but I think it should convey that it is about the time of all the tests that will be used to cover the subject.
from infection.
as I said on discord here, I also think this feature shouldn't sum all the tests' time covering mutated line to decide if mutant should be skipped or not, but instead check tests time individually.
In our docs explanation - https://infection.github.io/2020/08/18/whats-new-in-0.17.0/#Skip-S-mutations-that-are-over-specified-time-limit - we give an example with one integration test which takes more than %timeout%, but not with total time of all tests, that's why I think it's confusing at the moment.
By the way, there are 2 places where timeout
configuration affects Infection's behavior:
- we use timeout for Mutant Processes (if after mutation we have an infinite loop, it will be killed after
timeout
seconds, which is 10s by default). This happens when Mutant is already created and executed in separate process.
infection/src/Process/Factory/MutantProcessFactory.php
Lines 59 to 68 in 154822a
- we use
timeout
to compare with the sum of all tests inMutationTestingRunner
to decide if we even need to run particular Mutant. If not, Mutant process is not executed (so we are not wasting time here)
infection/src/Process/Runner/MutationTestingRunner.php
Lines 102 to 106 in 154822a
In this issue, we are discussing point 2.
Thoughts how I think it should work instead, given timeout
is 10s by default (please share your thoughts, I may be wrong!):
- if each test takes <10s individually - we mutate the code, run Mutant process, because each tests, executed from the fastest to the slowest, can potentially kill this Mutant.
- if
M
ofN
tests take >10s, we still should run Mutant process, because tests that take <10s indiviadually can potentially kill this Mutant. (optional optimization: do not run thoseM
tests as they will anyway timeout, see point 1 above - if
N
ofN
(all tests) take >10s, we should skip running this Mutant Process, cause anyway all the Mutant Processes (point 1) will timeout
from infection.
By the way, there are 2 places where timeout configuration affects Infection's behavior
This is the functional impact of this issue: if my tests take 100 ms, my timeout should be close to that to avoid wasting considerable time on actual mutation-induced timeouts. But I can't drop the timeout if it's just going to lead to all tests being skipped.
I'll look into the coversNothing annotation but I don't think that's going to be a satisfying workaround. I know my "unit" tests are actually integration tests but that's unfortunately all that's supported by the Symfony Console CommandTester.
from infection.
unfortunately all that's supported by the Symfony Console CommandTester.
What would define unit vs integration there is whether you use an instantiated command/application or you get one from the kernel or something with externally configured services.
Otherwise, using directly the command to test it is not effective: the command runner is the application and it enriches the command definition.
from infection.
In JUnit there are timings for every and each test. So we could calculate the exact time it requires to run a set of tests and use that. There should be no need for heuristics and guesswork.
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="phpunit.xml.dist" tests="2276" assertions="2489" errors="0" failures="0" skipped="0" time="5.511347">
<testsuite name="Main" tests="2276" assertions="2489" errors="0" failures="0" skipped="0" time="5.511347">
<testsuite name="Tests\Pipeline\ChunkTest" file="tests/ChunkTest.php" tests="25" assertions="25" errors="0" failures="0" skipped="0" time="0.083669">
<testsuite name="Tests\Pipeline\ChunkTest::testChunk" tests="24" assertions="24" errors="0" failures="0" skipped="0" time="0.081661">
<testcase name="testChunk with data set #23" file="tests/ChunkTest.php" line="77" class="Tests\Pipeline\ChunkTest" classname="Tests.Pipeline.ChunkTest" assertions="1" time="0.027784"/>
<testcase name="testChunk with data set #13" file="tests/ChunkTest.php" line="77" class="Tests\Pipeline\ChunkTest" classname="Tests.Pipeline.ChunkTest" assertions="1" time="0.002334"/>
<testcase name="testChunk with data set #9" file="tests/ChunkTest.php" line="77" class="Tests\Pipeline\ChunkTest" classname="Tests.Pipeline.ChunkTest" assertions="1" time="0.002521"/>
<testcase name="testChunk with data set #19"
file="tests/ChunkTest.php" line="77"
class="Tests\Pipeline\ChunkTest"
classname="Tests.Pipeline.ChunkTest"
assertions="1" time="0.002292"/>
^^^^^^^^^^^^^^^
(I guess it wasn't the case before, and at one point we had to use test suite-wide timings as only these were available.)
from infection.
Related Issues (20)
- nikic/php-parser 5 support HOT 3
- Clean project ApiPlatform + PhpUnit 11 + PHP 8.3.x -> nikic/php-parser minimum version bump needed HOT 3
- Upgrade `php-cs-fixer` and add more rules
- Randomly failing test HOT 2
- Gitlab logger errors when run outside git repository HOT 2
- GPG key expired HOT 3
- Excluded sources are being processed for mutation
- Fail to find testcase from Junit report (Pest) HOT 2
- Support for short circuit evaluation with assignment statements HOT 5
- GitLab Logger generates invalid links HOT 3
- Error when running infection (fatal: not a git repository (or any of the parent directories): .git) HOT 8
- git command might be not found HOT 4
- 0.29.* PHAR version throws Fatal Error: Undefined constant when running tests with PHP-Parser 4 HOT 8
- Function parameter default values aren't handled appropriately (code-coverage issue) HOT 1
- specify in what folders apply --only-covered HOT 2
- Add "include" option to configuration files.
- Very high memory usage HOT 20
- Force failure when there is a RuntimeError HOT 4
- Extend the MemoryLimiter with a configurable fallback memory limit HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from infection.