AST based PHP Mutation Testing Framework

Overview

Minimum PHP version: 7.4.0 Latest Stable Version Continuous Integration Build Status Scrutinizer Code Quality Infection MSI codecov Slack channel: #infection on the Symfony slack

Infection - Mutation Testing framework

Please read documentation here: infection.github.io

Contributing

Infection is an open source project that welcomes pull requests and issues from anyone. Before opening pull requests, please consider reading our short Contribution Guide.

Credits

This project is highly inspired from Pádraic Brady (@padraic)'s Humbug library. Humbug has since then been discontinued in favour of this project.

Comments
  • Symfony components 4

    Symfony components 4

    This makes infection compatible with Symfony 4 components.

    Since it's still in beta, ^3.0 will still be installed for tests - force v4 components by temporarily altering composer's config like so:

    {
        "name": "infection/infection",
        "description": "Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.",
        "keywords": ["mutation testing", "mutation framework", "testing", "coverage", "unit testing", "mutant"],
        "type": "library",
        "license": "BSD-3-Clause",
        "support": {
            "issues": "https://github.com/infection/infection/issues"
        },
        "authors": [
            {
                "name": "Maks Rafalko",
                "email": "[email protected]",
                "homepage": "https://twitter.com/maks_rafalko"
            }
        ],
        "autoload": {
            "psr-4": {
                "Infection\\": "src/"
            }
        },
        "autoload-dev": {
            "psr-4": {
                "Infection\\Tests\\": "tests/"
            },
            "files": ["tests/Helpers.php"]
        },
        "require": {
            "php": "^7.0",
            "nikic/php-parser": "^3.0",
            "symfony/console": "^4.0",
            "symfony/process": "^4.0",
            "symfony/finder": "^4.0",
            "sebastian/diff": "^1.4|^2.0",
            "pimple/pimple": "^3.0",
            "symfony/yaml": "^4.0",
            "padraic/phar-updater": "^1.0.4"
        },
        "require-dev": {
            "phpunit/phpunit": "^6.1",
            "mockery/mockery": "^1.0"
        },
        "minimum-stability": "beta",
        "bin": ["bin/infection"],
        "scripts": {
            "analyze": [
                "@php-cs-fixer",
                "@phpstan"
            ],
            "phpstan": [
                "wget -nc https://github.com/phpstan/phpstan/releases/download/0.8.4/phpstan.phar",
                "chmod a+x phpstan.phar",
                "./phpstan.phar analyse src tests --level=1 --no-interaction --no-progress"
            ],
            "php-cs-fixer": [
                "wget -nc http://cs.sensiolabs.org/download/php-cs-fixer-v2.phar",
                "chmod a+x php-cs-fixer-v2.phar",
                "./php-cs-fixer-v2.phar fix --config=.php_cs.dist -v --dry-run --stop-on-violation --using-cache=no --allow-risky=yes"
            ],
            "php-cs-fixer:fix": [
                "./php-cs-fixer-v2.phar fix --config=.php_cs.dist -v --allow-risky=yes"
            ]
        }
    }
    
    
    opened by luispabon 53
  • Concurrent mutation generator

    Concurrent mutation generator

    • [x] Doc PR https://github.com/infection/site/pull/157

    This PR has a goal of solving these two problems:

    • Currently Infection spends around 20-30 seconds at the start, or even more depending on where it runs, just to parse relevant files and assemble a list of mutations. Yet it spends a lot more time just waiting for a mutator process to finish running. And it spends even more time checking for uncovered mutations, one reason why we have #1064 and #1065.
    • At the same time Infection will buffer in an array all files and all mutations. This problem isn't the root problem for #705 because we have other places where we buffer a lot of things, but this PR is one step towards solving problems like #750.

    How's it done?

    Can we can spread these 20 seconds while Infection waits for mutated tests to finish? Yes, we can, and that's what this PR is trying to archive.

    Here we add an additional "streaming" mode of operation, when no progress is expected to be reported, which is when running with --no-progress option, to be used primarily during CI. Instead of counting files and mutations we stream them directly through a chain of generator functions and some iterators right as mutation testing happens.

    For example, with this PR it takes around same 50-60 seconds less time to run Infection on itself. Where before I almost never could make Infection finish for faster that a minute and a half because of that delay, now I can make it finish easy under one minute.

    As a side effect, with these changes it takes about same time to run Infection both considering and ignoring uncovered files:

    vendor/bin/phpunit --coverage-xml=build/logs/coverage-xml --log-junit=build/logs/junit.xml --stop-on-failure
    bin/infection --skip-initial-tests --coverage=build/logs -j32 --only-covered --no-progress
    bin/infection --skip-initial-tests --coverage=build/logs -j32 --no-progress
    

    Otherwise put, we no longer have one of two reasons for #1064. This isn't a performance issue any more.

    Surely, nothing fancy comes free. Applying this streaming approach we're can no longer know exact number of mutations we're testing against before the fact (when running with --no-progress), and therefore we can no longer show how much work is ahead. But since --no-progress implies that end result is more important, it should not be a problem. Live mutation report becomes similar to the following, with just the current count of mutations:

    M..M.M.......M............ME.MM.....M..E........M.   ( 1900)
    ..M..M.......M........M..M.M......M.........M...M.   ( 1950)
    ...M....................M.....M.....M..M......M...   ( 2000)
    MMMMM........M....................MMMMMMMMMMMMM.MM   ( 2050)
    MM.MMM..M.M.M.MM.MMMMMMMMMMMMMMMMMMMMMM....MMMMMMM   ( 2100)
    MMMMMMMMMMMMMMMMMMMM
    
    2416 mutations were generated:
        1585 mutants were killed
         310 mutants were not covered by tests
         514 covered mutants were not detected
           4 errors were encountered
           3 time outs were encountered
    
    Metrics:
             Mutation Score Indicator (MSI): 65%
             Mutation Code Coverage: 87%
             Covered Code MSI: 75%
    
    Please note that some mutants will inevitably be harmless (i.e. false positives).
    Dashboard report has not been sent: Build context could not be resolved.
    
    Time: 58s. Memory: 192.02MB
    

    Memory usage is about twice as less when using --no-progress. As this PR unlocks for us possibility to clean unneeded parts of our pipeline as we go, we will have a chance to have a more definite solution to the memory problem from #705 later.

    Try it

    A picture's worth a thousand words. Check out this branch, composer install, then:

    vendor/bin/phpunit --coverage-xml=build/logs/coverage-xml --log-junit=build/logs/junit.xml --stop-on-failure
    bin/infection --skip-initial-tests --coverage=build/logs -j8 
    bin/infection --skip-initial-tests --coverage=build/logs -j8 --no-progress
    

    Note the time and memory usage difference. Repeat the same commands with master.

    Builds on Travis are not the fastest, and with a low -jN, but compare:

    Blackfire Profile courtesy Theo seemingly confirms these observations.

    Concurrency is not parallelism

    We're not parallelising the whole thing yet, unfortunately. This is kinda hard to do in PHP, and generally hard to do. The whole process is entirely sequential as it was before, and the only things running in parallel are the mutant processes. But we make some effort to ensure we're not waiting for processes to finish doing absolutely nothing.

    While we're quite far from parallelising the whole thing, we're a making a step towards solving the problem from #705. For one, because we no longer buffer a lot of heavy stuff in number of places. We still do, but no longer in these "hot" places. For example, as a next step, we can stream reports of escaped mutations into a file, removing the need to keep them in memory until the end of the program.


    Please note that comments below may not be relevant to the current version of this text.

    Enhancement Performance 
    opened by sanmai 38
  • Problem with

    Problem with "Skipped"

    | Question | Answer | ------------| --------------- | Infection version | 0.17.2@31e4af4be7e7508bed086d8254f010a56ff79bea | Test Framework version | 9.2.6 | PHP version | 7.4.3 | Platform | Ubuntu | Github Repo | -

    In version 0.16.4 most mutations do not run in timeouts. However, after updating to version 0.17.2, some of these mutants will be "skipped".

    I also checked that the mutants with "skipped" are not generated by the new "instanceof" mutator.

    I don't understand exactly why this happens? Is this a bug or intentional behavior?

    Output Infection 0.17.2:

        ____      ____          __  _
       /  _/___  / __/__  _____/ /_(_)___  ____
       / // __ \/ /_/ _ \/ ___/ __/ / __ \/ __ \
     _/ // / / / __/  __/ /__/ /_/ / /_/ / / / /
    /___/_/ /_/_/  \___/\___/\__/_/\____/_/ /_/
    
    Infection - PHP Mutation Testing Framework version 0.17.2@31e4af4be7e7508bed086d8254f010a56ff79bea
    
    [notice] You are running Infection with PCOV enabled.
    #!/usr/bin/env php
    
    Running initial test suite...
    
    PHPUnit version: 9.2.6
    
     1739 [============================] 21 secs
    
    Generate mutants...
    
    Processing source code files: 943/943
    .: killed, M: escaped, U: uncovered, E: fatal error, T: timed out, S: skipped
    
    ..................................................   (  50 / 4095)
    ...............S..................................   ( 100 / 4095)
    <skip>
    ..................................................   (4050 / 4095)
    .............................................        (4095 / 4095)
    
    4095 mutations were generated:
        4055 mutants were killed
           0 mutants were not covered by tests
           0 covered mutants were not detected
           0 errors were encountered
           2 time outs were encountered
          38 mutants required more time than configured
    
    Metrics:
             Mutation Score Indicator (MSI): 100%
             Mutation Code Coverage: 100%
             Covered Code MSI: 100%
    
    Please note that some mutants will inevitably be harmless (i.e. false positives).
    
    Time: 12m 58s. Memory: 0.15GB
    

    Output Infection 0.16.4:

    You are running Infection with PCOV enabled.
    
        ____      ____          __  _
       /  _/___  / __/__  _____/ /_(_)___  ____
       / // __ \/ /_/ _ \/ ___/ __/ / __ \/ __ \
     _/ // / / / __/  __/ /__/ /_/ / /_/ / / / /
    /___/_/ /_/_/  \___/\___/\__/_/\____/_/ /_/
    
    Infection - PHP Mutation Testing Framework 0.16.4@c1ef0b16b3e8d171f10ba8bfe8b6c93d482a68b4
    #!/usr/bin/env php
    
    Running initial test suite...
    
    PHPUnit version: 9.2.6
    
     1741 [============================] 22 secs
    
    Generate mutants...
    
    Processing source code files: 943/943
    .: killed, M: escaped, S: uncovered, E: fatal error, T: timed out
    
    ..................................................   (  50 / 3950)
    ..................E...............................   ( 100 / 3950)
    <skip>
    ..................................................   (3900 / 3950)
    ..................................................   (3950 / 3950)
    
    3950 mutations were generated:
        3947 mutants were killed
           0 mutants were not covered by tests
           0 covered mutants were not detected
           1 errors were encountered
           2 time outs were encountered
    
    Metrics:
             Mutation Score Indicator (MSI): 100%
             Mutation Code Coverage: 100%
             Covered Code MSI: 100%
    
    Please note that some mutants will inevitably be harmless (i.e. false positives).
    
    Time: 12m 8s. Memory: 136.01MB
    
    Bug PR merged 
    opened by ingowalther 33
  • Infection fails with

    Infection fails with "Allowed memory size ... exhausted" for a project with a really big coverage

    | Question | Answer | ------------| --------------- | Infection version | 0.13.2 | Test Framework version | PHPUnit | PHP version | 7.2 | Github Repo | https://github.com/vimeo/psalm

    Extracted from https://twitter.com/sorsoup/status/1140021198765658118

    Infection seems to be crashing when I try to run it to check the test suite of Psalm - output at (link: https://circleci.com/gh/bdsl/psalm/232) circleci.com/gh/bdsl/psalm/…

    Don't know if I'm doing anything wrong.

    Command line:

    php -d memory_limit=12G ~/sites/infection/bin/infection --coverage=build/phpunit --only-covered --threads=4
    

    Output:

         ____      ____          __  _
        /  _/___  / __/__  _____/ /_(_)___  ____
        / // __ \/ /_/ _ \/ ___/ __/ / __ \/ __ \
      _/ // / / / __/  __/ /__/ /_/ / /_/ / / / /
     /___/_/ /_/_/  \___/\___/\__/_/\____/_/ /_/
    
    Running initial test suite...
    
    PHPUnit version: 7.5.12
    
        1 [============================] < 1 sec
    
    Generate mutants...
    
    Processing source code files:   0/543
    
    PHP Fatal error:  Allowed memory size of 268435456 bytes exhausted (tried to allocate 20480 bytes) in /infection/src/TestFramework/PhpUnit/Coverage/CoverageXmlParser.php on line 170
    

    So it fails with when the coverage data is being accumulated in the following lines of the code (depending on how much memory_limit is set

    Unfortunately, code coverage takes 2+ hours for Psalm, so here is a compressed archive of needed coverage files: https://www.dropbox.com/s/66tvd0tctfbdki3/phpunit.bz?dl=0 for commit https://github.com/vimeo/psalm/commit/4c57c67e2f1b821e2ef8aa0b00448ff24ce92201

    Bug PR merged 
    opened by maks-rafalko 33
  • Extract Test Framework Adapters to separate composer packages

    Extract Test Framework Adapters to separate composer packages

    Work is based on the following resources

    This is the RFC with detailed description of Package Design Principles applied to Infection, that show the benefits of splitting infection/infection to separate packages. The main topic here is Test Framework Adapters, but splitting Infection is not limited to them (see another RFC for extracting Mutators).

    For me, there are no doubts we will split it. The question is how deep we will go.

    Principles about package cohesion

    Common Reuse Principle

    Classes that are used together are packaged together

    We clearly violate this priciple. People who use only PHPSpec adapter should not download Codeception/PHPUnit adapters.

    At the moment, infection/infection contains classes that are not all used by everyone who uses Infection package in their project, so it violates the Common reuse principle. It also contains classes (the same classes actually) that are not closed against the same kinds of changes, so the package violates the Common closure principle. More on it later.

    Dependencies of Test Framework

    Another thing that shows we violate this package principle is that infection/infection requires symfony/yaml. The key thing is that Infection has nothing to do with YAML. It's a dependency of Codeception and PHPSpec adapters, but not Infection itself. Each time you use only PHPUnit adapter (and don't use Codeception/PHPSpec), you have

    • the code you don't really need, that is not executed
    • one more reason to be affected by additional dependency
    • one more possible conflicting dependency when install Infection via Composer; and so on

    Cohesion

    When we extract each Test Framework Adapter to a separate package, they will be coherent: all the classes a separate package contains are about the same thing. When user needs PHPUnit adapter, all the classes from infection/phpunit-adapter will be used together. And no classes will be used and downloaded from other adapters.

    The Common closure principle

    • The classes in a package should be closed together against the same kinds of changes. A change that affects a package affects all the classes in that package.
    • The primary justification for this principle is that we want a change to be limited to the smallest number of packages possible.

    When a new version of the package becomes available, the user will upgrade their project (composer update infection/infection) to require the new dependency version. But they only want to do so if the changes we made to the package have something to do with the way the package is used in their project, since every upgrade requires them to verify that the code still works correctly with the new version of our package.

    What does it mean to us? When we, for example, fix a bug for the code related to Codeception adapter, people who use only PHPSpec adapter should not be affected. They should not download the new version of infection/infection (this is how it works currently with the monolith), which may or may not have unwanted side-effects or just bring many unrelated changes from the repository. Instead, only infection/codeception-adapter would be updated.

    As a package maintainer you should follow the Common closure principle to prevent yourself from “opening” a package for all kinds of unrelated reasons. It helps you prevent bringing out new releases that are irrelevant to most of your users. With this goal in mind the principle advises you to put classes in different packages if they have different reasons to change.

    Page 153 - Principles of Package Design

    Another positive benefits:

    • we will be able to set version constraints for any dependency. See this my commit https://github.com/infection/infection/commit/73bb17a0f98d6fda67a276d29648e5a54170767d#diff-d9b88806f4deaae39c43c22fb7f31d0fR214-R228: it checks that codeception/codeception must be of ^3.1.1 version. This should not be done in the main repository, but only in adapter
    • we will be able to track packages statistics separately:
      • how many downloads infection/phpunit-adapter has, the growing (or not) installs diagram
      • is it popular or not (stars, dependents), etc.
    • we will be able to release test framework adapters independent of infection/infection. This is a big win since people who use PHPUnit only will not be affected by a bugfix (or new introduced bug, who knows) in the recently updated PHPSpec adapter's code

    In this section about cohesion in Package Principles, I conclude that we need to extract the following 3 separate packages from infection/infection:

    • infection/phpunit-adapter
    • infection/phpspec-adapter
    • infection/codeception-adapter

    Principles about packages coupling

    Imaging we already extracted Test Framework Adapters to separate packages. Now, let's think what for example infection/phpunit-adapter will depend on. Here we have a couple of ways to go:

    1. infection/phpunit-adapter depends on infection/infection and uses TestFrameworkAdapter interface located in the main infection/infection core package
    2. infection/phpunit-adapter depends on a small, abstract and highly stable package, e.g. infection/abstract-testframework-adapter wich contains only abstractions and probably DTOs for Test Framework Adapters (or infection/contracts, read below)

    The following coupling principles will help us determining which of the ways above is more suitable for Infection.

    The Stable Dependencies Principle (SDP)

    Let's start from definitions.

    • Stable package has no or few dependencies it depend on
    • Unstable package needs to be updated each time its dependencies upgraded
    • Responsible package has many dependents - packages that depend on this package
    • Irresponsible package is not used by any packages

    Packages that are more independent and responsible should be considered highly stable. Those are packages that don’t need to change because of a change in one of their dependencies, but they also can’t easily change themselves because other packages heavily depend on them.

    And here is the Stable Dependencies Principle:

    The dependencies between packages in a design should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable than it is.

    Actually, we can calculate the "instability value" and see how our packages can be designed and how this plays with this package design principle.

    Instability value

    There is a formula to measure Instability of any package.

    I = Cout / (Cin + Cout)

    where

    • I - instability
    • Cout - the number of classes outside the package that any class inside the package depends upon
    • Cin - the number of classes outside the package that depend on a class inside the package.

    I value will be between 0 and 1 where 1 indicates that the package is maximally unstable and 0 indicates that it is maximally stable.

    A highly stable package is responsible: it has many dependents, so Cin is a high number. A highly unstable package is very dependent. It has many dependencies, so Cout is a high number.

    How can our packages be designed? There are at least 2 possible ways.

    1. TestFrameworkInterface is inside infection/infection

    The first case, when the TestFrameworkInterface is placed inside infection/infection, and our Test Framework Adapters packages depend on infection/infection.

    test-framework-adapter(1)

    From the first look, this is a simple and working solution. But there is a big issue: if the infection/codeception-adapter would depend on infection/infection to get the TestFrameworkAdapter interface from there, we would need to update its dependencies each time infection/infection is changed, even when the change is absolutely unrelated to the adapter's behaviour.

    This is how the infection/codeception-adapter's composer.json would look like:

    {
        "require": {
            "symfony/yaml": "^3.4.29 || ^4.0 || ^5.0",
            "infection/infection": "^0.13 | ^0.14 | ^0.15 ... and so on"
        }
    }
    

    Each time a new infection/infection version is released (even with the changes irrelevant to infection/codeception-adapter), we will need to update composer.json file to make this adapter compatible with the new version. And each such update means we need to test it to avoid potentially broken integration between adapter and the core Infection. We don't know, whether the new release of infection/infection affects us or not, but we still need to adopt these changes, and composer outdated will really show that adapter's dependency is not up to date.

    We will end up with the similar PRs as this one, constantly updating infection/infection's versions.

    What about Instability value for this way of package relations?

    I = Cout / (Cin + Cout)

    instability-first

    Note: 14 is a number of packages infection/infection is currently depends on.

    This way of packages design is clearly violates the Stable Dependencies Principle, because infection/codeception-adapter with I=0.5 depends on a package infection/infection with a bigger I=0.875. But according to the Stable Dependencies Principle, the dependencies between packages should be “in the direction of the stability of the packages" (or "in the direction of decreasing Instability"). Hence a red line.

    2. TestFrameworkAdapter is inside highly stable infection/abstract-testframework-adapter

    So, we need to make infection/codeception-adapter (and other adapters) to depend on something more stable, more reliable. Here is what we can do:

    abstract-test-framework-adapter(1)

    infection/abstract-testframework-adapter is a highly stable because it depends on 0 packages. It has only 1 reason to change - changing the Public API of TestFrameworkAdapter.

    infection/codeception-adapter's composer.json in this case would be like this:

    {
        "require": {
            "symfony/yaml": "^3.4.29 || ^4.0 || ^5.0",
            "infection/abstract-testframework-adapter": "^1.0.0"
        }
    }
    

    Now, when the new version of infection/infection is released, our adapters are not affected. The really one reason to update adapter's dependency is when we change our abstraction, which is a rare thing.

    Here is how Instability values look like:

    instability-second

    In this example each package depends on more stable packages, which is what this principle tells us to do.

    There is a similar example that Mattias describes in his book about gaufrette/filesystem package:

    [...] After we moved the Gaufrette\Filesystem class and the Gaufrette\Adapter interface out of the main package and into a small and very stable package, it became a lot safer to use that class and/or interface in another package because the freshly created knplabs/gaufrette-filesystem-abstraction package is very stable.

    [...] The lesson to be learnt here is that when you have the ability to split a package into multiple packages with different levels of stability, you should do it. You will make it easier for people to use your code in their projects, without introducing any more instability.

    Page 216 - Principles of Package Design

    The Stable Abstractions Principle (SAP)

    Packages should depend in the direction of abstractness.

    Packages that are maximally stable should be maximally abstract. Instable packages should be concrete. The abstraction of a package should be in proportion to its stability.

    This principle again makes sure that the more abstract a package we depend on, the less chances it will be changed. Because usually changes are done in concrete classes/packages, but not abstract. Abstract packages supposed to be stable. Over a longer period of time it will stay the same.

    As in the previous principle, we can calculate the value of Abstractness.

    A = Cabstract / (Cconcrete + Cabstract)

    I will show the values only for the second case, when we have a infection/abstract-testframework-adapter:

    abstractness-second

    As you can see, infection/abstract-testframework-adapter is very stable (I=0) and highly abstract (A=1). This means that this package conforms to both Stable Dependencies and Stable Abstractions principles and is a fundamental block of the package hierarchy.

    By the way, it's ok adapters be non abstract (and quite instable), because such packages are real concrete implementation of some abstraction. And there is no doubt they will change during the time.

    What happens if an interface TestFrameworkAdapter is part of a highly unstable package infection/infection? The answer is:

    [...] Then it is consequently not safe to depend on that package. The unstable package is likely to change. The interface inherits the instability of its containing package.

    Page 221 - Principles of Package Design

    That's it.

    The Acyclic Dependencies Principle

    The dependency structure between packages must be a directed acyclic graph, that is, there must be no cycles in the dependency structure.

    We don't have another packages yet so we are not affected by cycles between packages ;)

    Misc

    infection/contracts repository

    Now, we see that we need to extract Test Framework Abstraction to a separate repository. But this is not the last one. We will have at least one more abstraction - MutatorInterface. So it will probably be convenient to not have 2 separate repositories for each abstraction, but one infection/constract. Anyway, I'm not suggesting to create it right now, let's start with infection/abstract-testframework-adapter and then we will see...

    PHAR prefixing and bundling all adapters together

    You can ask how are we goin to prepare our PHAR file after splitting Infection to different repositories and extracting Test Framework Adapters. The answer is very simple - we will always bundle Codeception, PHPUnit, PHPSpec repositories inside PHAR file. PHAR users even won't notice this splitting.

    Autodiscovering of Packages

    For those who uses Infection as a composer dependency.

    What is really interesting, is how we can install different "plugins" for Infection, be it Test Framework Plugin or other future plugins like custom Mutators. There is an approach of autodiscovering via composer packages, for example:

    • https://psalm.dev/docs/running_psalm/plugins/authoring_plugins/#authoring-composer-based-plugins
    • https://github.com/phpstan/extension-installer

    The idea is very simple. A package has a special type inside composer.json file, for example "type": "infection-plugin".

    {
        "name": "infection/codeception-testframework-adapter",
        "type": "infection-plugin",
        "require": {
            "php": "^7.2.9",
            "ext-dom": "*",
            "ext-libxml": "*",
            "symfony/yaml": "^3.4.29 || ^4.0 || ^5.0"
        },
        "conflict": {
            "codeception/codeception": "<3.1.1" // isn't it cool?
        },
    }
    

    Then, Infection analyzes composer.lock file and autoregister all Infection plugins. The end user will just do the following change in the project's composer.json:

    "infection/infection": "^0.15",
    + "infection/codeception-testframework-adapter": "^1.0.0"
    

    and it's done - Infection automatically finds a registers adapter.

    Of course, we will be able to add plugins in infection.json file as well. But autodiscovery is a cool feature.

    Last words

    We don't need to treat our abstract packages with extension points immediately final and stable for users from the very first release. No. This is just the first step to be able to use flexible and useful Packages. And only after we quite stabilize them, we can mark them public (it's not the same as 1.0.0) and generally available. Until then - these packages can be "private".

    At this point, I hope nobody have any doubts that we have to split Infection.

    Feature Request RFC 
    opened by maks-rafalko 28
  • symbolic link trouble + PHPUnit unknown

    symbolic link trouble + PHPUnit unknown

    | Question | Answer | ------------| --------------- | Infection version | 0.13.6 | Test Framework version | PHPUnit 7.5.15 | PHP version | 7.3.5 | Platform | Windows 10 Pro (using ConEmu) | Github Repo | https://github.com/ccwebdesign/infection-temp

    When run under a symbolic link in a terminal, infection creates all of the mutants, but claims they're all uncovered by tests.

    To reproduce:

    • create a directory with some code, tests, and Infection
    • create a symbolic link to that directory
    • cd into the symbolic link and run tests then infection

    Repository above contains samples and structure if you want it.

    Infection was run from the test subdirectory with:

    ..\..\vendor\bin\infection --coverage=tmp -j=4
    

    Separate issue is that the PHPUnit version is unknown, both in the symlink folder and the actual one. (Whether vendor/bin directory is or isn't in PATH.)

    Left out the phpunit.junit.xml for brevity (and since it's probably not relevant).

    Output with issue
    You are running Infection with Xdebug enabled.
        ____      ____          __  _
       /  _/___  / __/__  _____/ /_(_)___  ____
       / // __ \/ /_/ _ \/ ___/ __/ / __ \/ __ \
     _/ // / / / __/  __/ /__/ /_/ / /_/ / / / /
    /___/_/ /_/_/  \___/\___/\__/_/\____/_/ /_/
    
       0 [>---------------------------] < 1 secRunning initial test suite...
    
    PHPUnit version: unknown
    
       1 [============================] < 1 secProcessing source code files:   0/585
    
    Generate mutants...
    
    Processing source code files: 585/585Creating mutated files and processes:    0/6999
    Creating mutated files and processes: 6999/6999
    ...
    6999 mutations were generated:
          0 mutants were killed
       6999 mutants were not covered by tests
          0 covered mutants were not detected
          0 errors were encountered
          0 time outs were encountered
    
    Bug PR merged 
    opened by ccwebdesign 26
  • Add infection to PHIVE (PHAR Installation and Verification Environment)

    Add infection to PHIVE (PHAR Installation and Verification Environment)

    I'd love to be able to install infection via PHIVE. Steps needed to enable PHIVE support:

    1. Deploy a phive.xml file to your webserver, see here for the XSD or here for a project generating such a file
    2. Add the phive.xml url to list of PHIVE repositories
    Enhancement 
    opened by shochdoerfer 26
  • Refrain from adding filter tags if there are existing new-style coverage / include tags

    Refrain from adding filter tags if there are existing new-style coverage / include tags

    Since current PHPUnit will accept old-style filter / whitelist tags with a warning, it is should be enough to have Infection running if we avoid adding old-style tags if there are existing new-style coverage / include tags.

    This PR:

    • [x] Part to #1283
    • [x] Covered by tests
    Enhancement 
    opened by sanmai 24
  • Add github logger to be able to use Annotations on GitHub Actions

    Add github logger to be able to use Annotations on GitHub Actions

    This PR:

    • [x] Covered by tests
    • [x] Doc PR: https://github.com/infection/site/pull/183

    Fixes https://github.com/infection/infection/issues/1322

    Description

    This feature allows adding errors/warnings for particular commits/PRs - GitHub Annotations

    Basically, this feature adds escaped mutants information (diff) to particular lines where modified source code wasn't detected by tests:

    checkstyle

    Things to note

    • Unfortunately, GitHub Annotations does not allow using syntax highlighting inside annotations, so we can't display a pretty diff, as well as using <details> tag to be able to show/hide huge text.
    • Currently, I've added a separate GH Action to run Infection just for the added files in order to display warnings.
    • Displayed warnings does not fail the build

    Goal

    This will greatly improve review process as it will be immediately clear what parts of the code are not covered by tests properly (thus escaped mutants)

    Suggestions are appreciated.

    Feature 
    opened by maks-rafalko 23
  • Running on 7.4beta1 leads to notices while trying to run PHPUnit tests?

    Running on 7.4beta1 leads to notices while trying to run PHPUnit tests?

    | Question | Answer | ------------| --------------- | Infection version | 0.13.4 | Test Framework version | PHPUnit 8.2.5 | PHP version | PHP 7.4.0-dev (cli) (built: Jul 27 2019 09:27:41) ( ZTS ) | Platform | Ubuntu | Github Repo | https://github.com/Ocramius/ProxyManager

    I cannot seem to reproduce this locally, but I get this notice during infection/infection runs on travis-ci:

    Notice: stream_get_contents(): read of    
             8192 bytes failed with errno=9 Bad file descriptor in Standard input   
             code on line 321                                                       
    

    See https://travis-ci.org/Ocramius/ProxyManager/jobs/564695820#L2102-L2107

    "Bad file descriptor"

    This may be referring to a closed file handle?

    I already run with -vvv, so maybe I can try further flags to make the build in CI more verbose?

    Question 
    opened by Ocramius 23
  • Should infection keep using a json config?

    Should infection keep using a json config?

    Currently infection uses a json file as its configuration file. I don't know what the original reason was for a json file, but i'd like to find out if there are better options for us.

    We are at a stage where we could still make a transition between config styles, if there is a benefit to doing so. So i'd like to resolve this somewhere before 1.0.0

    Some viable options could be:

    • XML, like phpunit
    • YAML, like phpspec
    • PHP: like php-cs-fixer

    I think we should look at what the benefits and limitations of each configuration style are. And then decide if one style provides enough benefit to make the change.

    If we do decide to change we should still support the json configuration style for at least one minor version, and give a big deprecation warning.

    Question 
    opened by BackEndTea 23
  • The PestAdapter builds the PHPUnit configuration with the pest version instead of the PHPUnit version

    The PestAdapter builds the PHPUnit configuration with the pest version instead of the PHPUnit version

    | Question | Answer | ------------| --------------- | Infection version | 0.26.16 | Test Framework version | PHPUnit 9.5.27 and pestphp/pest 1.22.3 | PHP version | 8.1.14 | Platform | Doesn't matter | Github Repo | -

    I am running infection with the test runner pestphp/pest. While I was looking for a strange behaivor I could find a small (not intended?) bug. The PestAdapter uses the pest version instead of the PHPUnit version to create the phpunit config files.

    The partial stacktrace should be a prove

    #0 ...\vendor\infection\infection\src\TestFramework\AbstractTestFrameworkAdapter.php(111): Infection\TestFramework\AbstractTestFrameworkAdapter->retrieveVersion()
    #1 ...\vendor\infection\infection\src\TestFramework\AbstractTestFrameworkAdapter.php(121): Infection\TestFramework\AbstractTestFrameworkAdapter->getVersion()
    #2 ...\vendor\infection\infection\src\TestFramework\AbstractTestFrameworkAdapter.php(76): Infection\TestFramework\AbstractTestFrameworkAdapter->buildInitialConfigFile()
    #3 ...\vendor\infection\infection\src\TestFramework\PhpUnit\Adapter\PhpUnitAdapter.php(108): Infection\TestFramework\AbstractTestFrameworkAdapter->getInitialTestRunCommandLine('--coverage-xml=...', Array, false)
    #4 ...\vendor\infection\infection\src\TestFramework\PhpUnit\Adapter\PestAdapter.php(89): Infection\TestFramework\PhpUnit\Adapter\PhpUnitAdapter->getInitialTestRunCommandLine('--coverage-xml=...', Array, false)
    ...
    

    This will result in calling pest --version with the output:

    Pest    1.22.3
    PHPUnit 9.5.27 by Sebastian Bergmann and contributors.
    

    an results into 1.22.3 wich is totaly correct, but not usable for the MutationConfigBuilder.

    TLDR: The configuration for a unit test will not include any PHPUnit Version related configuration adjustments like enabling result cache, set the execution order etc.

    Let me know if i have to share more informations

    Bug Not Confirmed 
    opened by MOuli90 1
  • Fix coverage failure in case of an invalid file

    Fix coverage failure in case of an invalid file

    This PR:

    • [ ] Adds new feature ...
    • [ ] Covered by tests
    • [ ] Doc PR: https://github.com/infection/site/pull/XXX

    My lib supports two incompatible versions of a dependency. Code for older version extends class that does not exist in newer one. Currently code coverage fails with Uncaught Error: Class "Latte\Macros\MacroSet" not found https://github.com/orisai/localization/actions/runs/3766779916/jobs/6403641877 (shown run uses only temporary commit, I also had to do the same fix in https://github.com/sebastianbergmann/php-code-coverage/pull/973)

    After applying the fix, coverage no longer fails. And file is correctly reported as uncovered. https://github.com/orisai/localization/commit/a0f7a0b766c738d0df99eed52f8f529aceabb4f3 https://github.com/orisai/localization/actions/runs/3766885353

    opened by mabar 0
  • refactor(ci): Extract unit & integration tests from the CI workflow

    refactor(ci): Extract unit & integration tests from the CI workflow

    I think the end-to-end workflow is quite complex and hard to work with. There is several concerns brought by the nature of end-to-end tests and they also tend to be inherently slow. This makes it hard to further tweak the configuration and test a wider range of constraints.

    I'm proposing to extract the unit & integration tests. This will allow to diversify the build to test:

    • A wider range of operating systems
    • More different PHP versions
    • Highest/lowest or locked versions
    • Specific Symfony versions

    A PoC of that work can be seen in #1786.

    ⚠️ Requires to update the project settings afterwards as the build name changes

    opened by theofidry 0
  • Draft: refactor(ci): Run the unit & integration tests in another workflow

    Draft: refactor(ci): Run the unit & integration tests in another workflow

    I think this will make it easier to adjust the tests to run future PHP versions or different Symfony versions.

    We could of course do it with the e2e tests but the CI is already quite long, I don't think we want to run the e2e tests for all the variants.

    Depends on #1787.

    ⚠️ Requires to update the project settings afterwards as the build name changes

    opened by theofidry 1
  • PHP Warning on startup when using Infection from PHAR

    PHP Warning on startup when using Infection from PHAR

    I am using Infection in a project that has a composer.json file as well as a vendor/autoload.php file but no vendor/composer/InstalledVersions.php file since no dependencies are defined in composer.json:

    $ ./tools/infection --version
    PHP Warning:  include(/path/to/project/vendor/composer/../composer/InstalledVersions.php): Failed to open stream: No such file or directory in phar:///path/to/project/tools/infection/.box/vendor/composer/ClassLoader.php on line 571
    PHP Warning:  include(): Failed opening '/path/to/project/vendor/composer/../composer/InstalledVersions.php' for inclusion (include_path='.:/usr/share/pear:/usr/share/php:/usr/share/pear:/usr/share/php') in phar:///path/to/project/tools/infection/.box/vendor/composer/ClassLoader.php on line 571
    Infection - PHP Mutation Testing Framework version 0.26.16
    

    It appears that Infection assumes that vendor/composer/InstalledVersions.php always exists and unconditionally tries to open it.

    Bug 
    opened by sebastianbergmann 4
Releases(0.26.16)
Owner
Infection - Mutation Testing Framework for PHP
AST based Mutation Testing Framework for PHP
Infection - Mutation Testing Framework for PHP
SimpleTest is a framework for unit testing, web site testing and mock objects for PHP

SimpleTest SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Installation Downloads All downloads are stored on G

SimpleTest 147 Jun 20, 2022
The modern, simple and intuitive PHP unit testing framework.

atoum PHP version atoum version 5.3 -> 5.6 1.x -> 3.x 7.2 -> 8.x 4.x (current) A simple, modern and intuitive unit testing framework for PHP! Just lik

atoum 1.4k Nov 29, 2022
Full-stack testing PHP framework

Codeception Modern PHP Testing for everyone Codeception is a modern full-stack testing framework for PHP. Inspired by BDD, it provides an absolutely n

Codeception Testing Framework 4.6k Jan 7, 2023
The PHP Unit Testing framework.

PHPUnit PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks. Installat

Sebastian Bergmann 18.8k Jan 4, 2023
PHP unit testing framework with built in mocks and stubs. Runs in the browser, or via the command line.

Enhance PHP A unit testing framework with mocks and stubs. Built for PHP, in PHP! Quick Start: Just add EnhanceTestFramework.php and you are ready to

Enhance PHP 67 Sep 12, 2022
Pest is an elegant PHP Testing Framework with a focus on simplicity

Pest is an elegant PHP Testing Framework with a focus on simplicity. It was carefully crafted to bring the joy of testing to PHP. Explore the docs: pe

PEST 5.9k Dec 27, 2022
A drop in fake logger for testing with the Laravel framework.

Log fake for Laravel A bunch of Laravel facades / services are able to be faked, such as the Dispatcher with Bus::fake(), to help with testing and ass

Tim MacDonald 363 Dec 19, 2022
Unit testing tips by examples in PHP

Unit testing tips by examples in PHP Introduction In these times, the benefits of writing unit tests are huge. I think that most of the recently start

Kamil Ruczyński 894 Jan 4, 2023
PHP libraries that makes Selenium WebDriver + PHPUnit functional testing easy and robust

Steward: easy and robust testing with Selenium WebDriver + PHPUnit Steward is a set of libraries made to simplify writing and running robust functiona

LMC s.r.o. 219 Dec 17, 2022
PHPArch is a work in progress architectural testing library for PHP projects

PHPArch What is this? Installation Simple Namespace validation Available Validators Defining an architecture Syntactic sugar: Bulk definition of compo

Johannes Hertenstein 236 Nov 28, 2022
An effort to make testing PHP code as easy and fun as its JavaScript equivalent

An effort to make testing PHP code as easy and fun as its JavaScript equivalent when using the excellent Jasmine, from which syntax and general usage is shamelessly borrowed.

Johan Stenqvist 24 Apr 22, 2022
:computer: Parallel testing for PHPUnit

ParaTest The objective of ParaTest is to support parallel testing in PHPUnit. Provided you have well-written PHPUnit tests, you can drop paratest in y

null 2k Dec 31, 2022
Few additional testing assertions for Laravel views

Laravel View Test Assertions Few additional assertions for testing Laravel views. Why Laravel has well established and documented way of testing reque

null 13 Jun 12, 2022
Real-world Project to learning about Unit Testing/TDD with Laravel for everybody

KivaNote - a Laravel TDD Sample Project Let me introduce you to KivaNote, a simple real-world application using Laravel to show you how the TDD & Unit

(Seth) Phat Tran 10 Dec 31, 2022
Package for unit testing Laravel form request classes

Package for unit testing Laravel form request classes. Why Colin DeCarlo gave a talk on Laracon online 21 about unit testing Laravel form requests cla

null 18 Dec 11, 2022
Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slowness of constantly restarting the testing environment.

Magic Test for Laravel Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slownes

null 400 Jan 5, 2023
A video course for laravel artisan to learn creating API using testing

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Bitfumes 16 Oct 6, 2022
PHPUnit extension for database interaction testing.

This extension is no longer maintained DbUnit PHPUnit extension for database interaction testing. Installation Composer If you use Composer to manage

Sebastian Bergmann 224 Aug 20, 2022