- Guide
- Playground
- GitHub
-
Ecosystem
Help
Resource Lists
Recent Posts
- What's new in Infection 0.26.0
- What's new in Infection 0.25.0
- What's new in Infection 0.24.0
- What's new in Infection 0.23.0
- What's new in Infection 0.21.0
- What's new in Infection 0.20.0
- What's new in Infection 0.19.0
- What's new in Infection 0.18.0
- What's new in Infection 0.17.0
- What's new in Infection 0.16.0
What's new in Infection 0.11.0
Nov 12, 2018
Release: https://github.com/infection/infection/releases/tag/0.11.0
BC Breaks
Before upgrading, make sure you know about backward incompatible changes.
The following mutators have beed removed from the @default
profile:
==
→===
!=
→!==
===
→==
!==
→!=
In order to use them, you should explicitly enable them in infection.json
.
New features and enhancements
Random order of tests for PHPUnit
Did you know that PHPUnit can run the tests in a random order out of the box, starting from version 7.2
?
Now, Infection will use this feature and run your tests randomized in order to check if they pass during the so-called “Initial Tests Run” step.
Why is it needed?
It’s needed to be sure that the tests in your project do not have hidden dependencies. During mutation testing, Infection executes only those tests for each Mutant, that covers a mutated line of the code. And the order of those tests is always fastest - first
.
Thus, if the sorted order differs from the default one, and it leads to tests fail because of tests dependencies, Infection will incorrectly mark such Mutant as killed which will impact MSI.
How does it works?
The following attributes are added to phpunit.xml
:
executionOrder="random"
resolveDependencies="true"
Why do we need resolveDependencies
?
If some tests depend on each other through @depends
annotation, then running them in a random order will lead to skipped broken tests. To avoid reordering such dependent tests and still use randomness, we should use resolveDependencies="true"
(or --resolve-dependencies
option)
Read more about this PHPUnit feature: https://github.com/epdenouden/phpunit/wiki/PHPUnit-test-running-order-management#demo-3-handling-dependencies
PHPUnit’s @codeCoverageIgnore
annotations support
Infection now supports @codeCoverageIgnore
annotation on class and method level.
The following class will not be mutated, because it does not produce any code coverage.
/** |
In this example, method generate()
will be skipped from mutation logic, but getDependencies()
will be mutated as the usual method.
class ProductFixture |
infection.json
schema validation
We are constantly improving DX in Infection and one of the new enhancements is a JSON Schema validation of infection.json
.
No more typos, extra fields and incorrect keys!
phpunit.xml
XSD validation
One of the most popular issues when Infection does not work properly on your projects is when there is an invalid phpunit.xml
. In order to reduce the number of such issues, we’ve added XSD validation.
It works with a remote and a local XSD files:
https://schema.phpunit.de/6.1/phpunit.xsd
./vendor/phpunit/phpunit/phpunit.xsd'
Just make sure you have it in your phpunit.xml
:
<?xml version="1.0" encoding="UTF-8"?> |
Multiple mutations from one Mutator
Previously, one Mutator class could produce only one Mutation. For example Plus
mutator mutates binary +
operator to binary -
- $a = $b + $c; |
It works fine, but in practice we found more complex cases where it would be easier to mutate one Node
to multiple Node
s from the same class. For example, let’s look at the RoundingFamily
Mutator.
- it mutates
floor()
toceil()
ANDround()
- it mutates
ceil()
tofloor()
ANDround()
- it mutates
round()
toceil()
ANDfloor()
This is possible thanks to Generators. Now each Mutator can yield
as many mutations as needed.
- $result = round($percentage, 2); |
New Mutators
RoundingFamily
- it mutates
floor()
toceil()
ANDround()
- it mutates
ceil()
tofloor()
ANDround()
- it mutates
round()
toceil()
ANDfloor()
We’ve added a new mutators profile that unwraps parameters from functions.
Note that some of them produce multiple mutations depending on the number of possible arguments.
UnwrapArrayChunk
This mutator takes the first argument of array_chunk()
function and assigns it to the variable. Are your tests ready to kill such Mutant?
- $a = array_chunk(['A', 'B', 'C'], 2); |
UnwrapArrayCombine
- $a = array_combine(['A', 'B', 'C'], ['foo', 'bar', 'baz']); |
UnwrapArrayDiff
- $a = array_diff(['A', 'B', 'C'], ['D']); |
UnwrapArrayFilter
- $a = array_filter(['A', 1, 'C'], 'is_int'); |
UnwrapArrayFlip
- $a = array_flip(['A', 'B', 'C']); |
UnwrapArrayIntersect
- $a = array_intersect(['A', 'B', 'C'], ['D']); |
UnwrapArrayKeys
- $a = array_keys(['foo' => 'bar']); |
UnwrapArrayMap
- $a = array_map('strtolower', ['A', 'B', 'C'], \Class_With_Const::Const, $foo->bar()); |
UnwrapArrayMerge
- $a = array_merge(['A', 'B', 'C'], ['D']); |
UnwrapArrayReduce
- $a = array_reduce(['A', 'B', 'C'], $callback, ['D']); |
UnwrapArrayReplace
- $a = array_replace(['A', 'B', 'C'], ['D']); |
UnwrapArrayReplaceRecursive
- $a = array_replace_recursive(['A', 1, 'C'], ['D'], ['E', 'F']); |
UnwrapArrayReverse
- $a = array_reverse(['A', 'B', 'C']); |
UnwrapArrayUnique
- $a = array_unique(['foo', 'bar', 'bar']); |
UnwrapArrayValues
- $a = array_values(['foo' => 'bar']); |
Getting bored? A couple of string-related mutators:
UnwrapStrRepeat
- $a = str_repeat('A', 3); |
UnwrapStrToLower
- $a = strtolower('Hello!'); |
UnwrapStrToUpper
- $a = strtoupper('Hello!'); |