Using Poodle#
Getting Started#
The most important thing is to tell poodle where your source code is. By default, it will look for a folder named “src” or “lib”. But if the parent folder for your project is something else, you’ll need to tell poodle where to look.
Tip
In some systems it’s necessary to prefix poodle command like: python3 -m poodle
Project with “src” folder:
Example:
src
main.py
util.py
query
__init__.py
database.py
test
__init__.py
test_main.py
test_util.py
pyproject.toml
requirements.txt
Running with just poodle
will find the folder.
Project with “sources” folder:
Example:
sources
main.py
util.py
query
__init__.py
database.py
tests
__init__.py
test_main.py
test_util.py
pyproject.toml
requirements.txt
In this case, need to specify source folder like: poodle sources
DO NOT specify the package folders like “sources/query” as a source. Poodle needs the folder that contains the package folder.
Project with multiple sources to mutate:
Example:
application
main.py
query
__init__.py
database.py
layer
util.py
tests
__init__.py
test_main.py
test_util.py
pyproject.toml
requirements.txt
You can specify multiple folders to mutate like: poodle application layer
DO NOT specify the package folders like “application/query” as a source. Poodle needs the folder that contains the package folder.
Flat project:
Example:
query
__init__.py
database.py
main.py
pyproject.toml
requirements.txt
test_main.py
test_util.py
util.py
In this case, specify the source as the current folder: poodle .
DO NOT specify the package folders like “query” as a source
Flat Package project:
Example:
app
__init__.py
main.py
util.py
query
__init__.py
database.py
test
__init__.py
test_main.py
test_util.py
pyproject.toml
requirements.txt
In this case, specify the source as the current folder: poodle .
DO NOT specify the package folders like “app” or “app/query” as a source. Poodle needs the folder that contains the package folder.
Configuration File#
Poodle accepts several types of configuration files.
First is you can create poodle_config.py
module. This is the most flexible option especially if you are adding custom code.
Second is a key/value config file like pyproject.toml
or poodle.toml
. All options are listed in the Options page.
if you need to specify folders for your project, recommend putting that setting in your chosen config file with option source_folders
Start Small#
If you have a lot of modules to scan, it can be helpful to start by scanning one or two at a time. This can be accomplished with the --only
flag.
poodle --only main.py --only database.py
Terminology#
Mutation Testing can introduce some confusing language. For example, we run the test suite and a test case failed. In mutation testing, we want to testing to fail, so the test suite passed. passed == failed?
So, in this application, I use the following terms whenever possible to help make things clearer
- Mutation
An intentional bug added to the code. For example, changing
x + y
tox - y
.- Trial
A run of the entire test suite. Usually to validate if the Test Suite can find the Mutation.
- Passed
When a Test Suite or Test Case ends without an error.
- Failure
When a Test Suite or Test Case ends with an error or non-successful return code.
- Found
If a Trial of a Mutation results in a Failure, then the Mutation was Found.
- Not Found
If a Trial of a Mutation results in a successful completion, then the Mutation was Not Found.
- Timeout
If the time to run a Trial exceeds a reasonable limit, the Trial is reported as Timeout instead of Found or Not Found.
- Errors
If a Trial results in an exception that is not normally expected from the Test Suite.
Whitelisting#
Whitelisting is used to prevent mutations from being tested. This can be helpful in cases where mutation can’t reasonably be tested. There are several methods to whitelist code in poodle.
Line Comments#
The best way to block a mutation on a specific line is to add a comment to the line.
x = y + 3 # nomut: Number
x = y + 3 # nomut: Number, BinOp
x = y + 3 # nomut
or
x = y + 3 # nomut: all
or
x = y + 3 # pragma: no mutate
x = y + 3 # nomut: start
x += 4
y *= 6 # nomut: end
or
x = y + 3 # nomut: on
x += 4
y *= 6 # nomut: off
Whitelisting Entire Files#
The best way to prevent mutation on an entire file is to add it to the file_filters option in your configuration file.
Disabling a Mutator#
You can also disable a mutator completely using the skip_mutators option in your configuration file.
Create a Badge#
Like Badges, heres how I created this one:
Enter the following data:
URL: Enter link to the RAW JSON report file that includes summary data.
Query: $.summary.coverage_display
Label: Mutation Coverage
Color: 3776b5
Logo: (optional)
data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYuOTMzbW0iIGhlaWdodD0iMTMuNTNtbSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMTYuOTMzIDEzLjUzIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxnIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjEyODYiPjxwYXRoIGQ9Im0zLjEwMDIgMTIuODA0Yy0xLjA2NjItMC41NzEzOC0xLjk3MzUtMS41MTctMi4yMjgyLTIuNzI5OC0wLjM3ODA3LTEuNTU4OS0wLjM1MTE1LTMuMTk0MS0wLjE0NDc0LTQuNzc1IDAuMjE3OTQtMS4zODUgMS4zNjQzLTIuMzQ1NCAyLjQxMjQtMy4xNTI3IDAuOTk3NzQtMC42NzIwMSAyLjEwMzMtMS4yNjM1IDMuMjg3Ny0xLjQ5OTUgMS40MjY3LTAuMTcxNTcgMy4xMzQ0LTAuMTY3ODcgNC4xNTg5IDEuMDA4NiAwLjQ5OTQxIDAuNTI4NTEgMC42OTI5NiAxLjI1NzkgMC42MjI4NSAxLjk2OS0wLjAwNDkgMC44OTcxNCAwLjMwMzkzIDEuOTA3OCAxLjE4IDIuMzE0MyAxLjE0MzkgMC42NTU2OCAyLjUzMDggMC41NTMxMSAzLjcyMTQgMS4wODA4IDAuNzE1OTQgMC43MzgzMi0wLjI1NTQ2IDEuNjMzOC0wLjUxMDYxIDIuMzY1LTAuMzM5MDEgMC45MzMyLTEuMjkzOCAxLjIzNzYtMi4xMzMxIDEuNTQ5Ni0xLjYzNDggMC42NDgzNC0zLjExNTkgMC45NjU3NS01LjIwNTcgMS40MTAzLTIuNzcxMyAwLjcwMjA4LTMuODU0MSAwLjc0ODExLTUuMTYwOSAwLjQ1OTI3eiIgZmlsbD0iIzM3NzZiNSIvPjxwYXRoIGQ9Im0xNS4wMTcgOS40ODYyYy0wLjY4NjM5IDAuMDcyMzA4LTEuNDAxNS0xLjIzNjQtMS4zNDc4LTEuOTc4NSAwLjIwODIxLTAuOTk3NDcgMC44NDk1NS0wLjI1MTkzIDEuMTI1NC0wLjM5OTQgMC4yNTMzNC0wLjEzNDMxIDAuNTEyMTYtMC4xNjYzMSAwLjc3ODk2LTAuMDQ5MzI0IDAuNjA1NzMgMC4zMzk2OCAwLjExNDY0IDEuMjg2Ny0wLjEzNzY2IDEuNzUzOHoiLz48ZWxsaXBzZSBjeD0iOS4zMDM2IiBjeT0iNi4zOTUiIHJ4PSIxLjM0ODEiIHJ5PSIuODA0MDEiLz48L2c+PHBhdGggZD0ibTQuNzc3OSA0LjA3YzAuNjk1ODggMC4zMDQzMiAwLjYwODk5IDAuMzQwMjYgMC41OTUyNiAwLjkxMjk2LTAuMDExNTI1IDEuNjg0MiAwLjY0ODUyIDMuMzU1OCAwLjYwMzg5IDUuMTAxMiAwLjAxNTY2MyAwLjc1NjMzLTAuMDY2MTc3IDAuODQ3NzMtMC4zOTg5NiAxLjc2NDYtMC43NDMyNiAwLjM0MjAyLTEuNDQwOCAwLjE1ODY0LTIuMjc4LTAuMDA1MzM4LTAuODczNDgtMC42MTc4NC0xLjAxODktMC43NTkzMi0xLjQxODQtMi4wMDYzLTAuMzI0MjUtMS44NjQzLTAuMzIwMzYtMy4yOTM3LTAuMDgyODQ2LTQuOTU5NiAwLjE4OTYxLTAuOTY0NTEgMi42MjMyLTAuOTYxNzQgMi45Nzg5LTAuODA3NTYiIGZpbGw9IiMzNzNjNDMiIHN0cm9rZT0iIzM3M2M0MyIgc3Ryb2tlLXdpZHRoPSIxLjEyODYiLz48L3N2Zz4=