Quickstart
Eager to start? Make sure that Pynguin is installed properly.
Warning
Pynguin actually executes the code of the module under test. That means, if the code you want to generate tests for does something bad, for example wipes your disk, there is nothing that prevents it from doing so! This also includes code that is transitively imported by the module under test.
To mitigate this issue, we recommend running Pynguin in a Docker container with
appropriate mounts from the host system’s file system.
See the pynguin-docker.sh script in Pynguin’s source repository for documentation
on the necessary mounts.
To help prevent harming the system that runs Pynguin, its CLI will immediately abort
unless the environment variable PYNGUIN_DANGER_AWARE is set. In setting this
variable, you acknowledge that you are aware of the possible dangers of executing code
with random inputs. The assigned value can be arbitrary; Pynguin solely checks
whether the variable is defined.
We do not provide any support and are not responsible if you break your computer by executing Pynguin on some random code from the internet! Be careful and check the code before actually executing it—which is good advice anyway.
Developers: If you know of a similar technique to Java’s security manager mechanism in Python, which we can use to mitigate this issue, please let us know.
A Simple Example
For a first impression, we use the bundled example file and generate tests for it.
Note that this assumes that you have the source code checked out, installed Pynguin
properly—as mentioned before, we recommend a virtual environment, which needs to be
sourced manually—and that your shell is pointing to the root directory of Pynguin’s
source repository.
We run all commands on a command-line shell where we assume that the environment variable
PYNGUIN_DANGER_AWARE is set.
Note
We don’t use docker in our examples, because we know that our examples do not contain or use code that might harm our system. But for unknown code we highly recommend using some form of isolation.
First, let’s look at the code of the example file (which is located in
docs/source/_static/example.py):
1def triangle(x: int, y: int, z: int) -> str:
2 if x == y == z:
3 return "Equilateral triangle"
4 if x in {y, z} or y == z:
5 return "Isosceles triangle"
6 return "Scalene triangle"
The example is the classical triangle example from courses on Software Testing,
which yields for three given integers—assumed to be the lengths of the triangle’s
edges—what type of triangle it is.
Note that we have annotated all parameter and return types, according to
PEP 484.
Before we can start, we create a directory for the output (this assumes you are on a Linux or macOS machine, but similar can be done on Windows) using the command line:
$ mkdir -p /tmp/pynguin-results
We will now invoke Pynguin (using its default test-generation algorithm) to let
it generate test cases (we use \ and the line breaks for better readability here,
you can just omit them and type everything in one line):
$ pynguin \
--project-path ./docs/source/_static \
--output-path /tmp/pynguin-results \
--module-name example
This runs for a moment without showing any output. Thus, to have some more verbose
output we add the -v parameter:
$ pynguin \
--project-path ./docs/source/_static \
--output-path /tmp/pynguin-results \
--module-name example \
-v
The output on the command line might be something like the following:
[09:01:14] INFO Starting Pynguin client with master-worker architecture client.py:40
INFO [Worker-36230] Worker process started (PID: 36230) worker.py:97
INFO [Worker-36230] Start Pynguin Test Generation… generator.py:141
INFO [Worker-36230] Collecting static constants from module under test generator.py:265
INFO [Worker-36230] No constants found generator.py:268
INFO [Worker-36230] Setting up runtime collection of constants generator.py:275
INFO [Worker-36230] Analyzed project to create test cluster module.py:1690
INFO [Worker-36230] Modules: 1 module.py:1691
INFO [Worker-36230] Functions: 1 module.py:1692
INFO [Worker-36230] Classes: 11 module.py:1693
INFO [Worker-36230] Using seed 1764316873425242000 generator.py:245
INFO [Worker-36230] Using strategy: Algorithm.DYNAMOSA generationalgorithmfactory.py:297
INFO [Worker-36230] Instantiated 9 fitness functions generationalgorithmfactory.py:385
INFO [Worker-36230] Using CoverageArchive generationalgorithmfactory.py:339
INFO [Worker-36230] Using selection function: Selection.RANK_SELECTION generationalgorithmfactory.py:314
INFO [Worker-36230] No stopping condition configured! generationalgorithmfactory.py:113
INFO [Worker-36230] Using fallback timeout of 600 seconds generationalgorithmfactory.py:114
INFO [Worker-36230] Using crossover function: SinglePointRelativeCrossOver generationalgorithmfactory.py:327
INFO [Worker-36230] Using ranking function: RankBasedPreferenceSorting generationalgorithmfactory.py:347
INFO [Worker-36230] Start generating test cases generator.py:606
INFO [Worker-36230] Initial Population, Coverage: 1.000000 searchobserver.py:75
INFO [Worker-36230] Algorithm stopped before using all resources. generator.py:609
INFO [Worker-36230] Stop generating test cases generator.py:614
INFO [Worker-36230] Minimizing test cases generator.py:623
INFO [Worker-36230] Removed 2 statement(s) from test casesusing CASE minimization generator.py:777
INFO [Worker-36230] Coverage after minimization is the same as before: [1.0] generator.py:716
INFO [Worker-36230] Start generating assertions generator.py:898
INFO [Worker-36230] Setup mutation generator generator.py:871
INFO [Worker-36230] Import module example generator.py:874
INFO [Worker-36230] Build AST for example generator.py:877
INFO [Worker-36230] Mutate module example generator.py:881
INFO [Worker-36230] Generated 13 mutants generator.py:891
INFO [Worker-36230] Running tests on mutant 1/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 2/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 3/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 4/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 5/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 6/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 7/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 8/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 9/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 10/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 11/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 12/13 assertiongenerator.py:276
INFO [Worker-36230] Running tests on mutant 13/13 assertiongenerator.py:276
INFO [Worker-36230] Mutant 0 killed by Test(s): 0, 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 1 killed by Test(s): 0, 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 2 killed by Test(s): 0, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 3 killed by Test(s): 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 4 killed by Test(s): 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 5 killed by Test(s): 0, 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 6 killed by Test(s): 0, 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 7 killed by Test(s): 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 8 killed by Test(s): 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 9 killed by Test(s): 0, 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 10 killed by Test(s): 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 11 killed by Test(s): 0, 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Mutant 12 killed by Test(s): 1, 2 assertiongenerator.py:378
INFO [Worker-36230] Number of Surviving Mutant(s): 0 (Mutants: ) assertiongenerator.py:390
INFO [Worker-36230] Calculating resulting FinalBranchCoverage generator.py:534
INFO [Worker-36230] Written 3 test cases to /private/tmp/pynguin-results/test_example.py generator.py:1007
INFO [Worker-36230] Writing statistics stats.py:368
INFO [Worker-36230] Stop Pynguin Test Generation… generator.py:146
INFO [Worker-36230] Worker completed task: test_gen_1764316874.5722592 worker.py:110
INFO Received result for task test_gen_1764316874.5722592: WorkerReturnCode.OK master.py:133
INFO Stopping master-worker system client.py:44
INFO Master-worker system stopped client.py:46
The first few lines show that Pynguin starts using a master-worker
architecture, which allows automatic restarting the test generation
in case of unexpected errors. Then, we see that Pynguin tries collecting
constants from the module under test, but none were found in this case.
Pynguin analyzes the module and finds one function, namely triangle,
which it will try to cover with generated test cases.
The eleven found classes are the built-in types that are always present.
Pynguin has not gotten any seed for its (pseudo) random-number generator,
so it generates one itself. We see some information about the
(default) configuration options used. We use, for example, the DYNAMOSA
algorithm. Pynguin ran zero iterations of that algorithm, i.e.,
the initial random test cases were sufficient to cover all branches.
This was to be expected, since the triangle example can be trivially covered with tests.
Pynguin minimizes the test suite and then generates assertions
using Mutation Analysis.
Before stopping the master-worker system, the results are printed:
Three test cases were written to /tmp/pynguin/results/test_example.py, which look
like the following (the result can differ on your machine):
1import example as module_0
2import builtins as module_1
3
4
5def test_case_0():
6 float_0 = 2530.058
7 int_0 = 3137
8 str_0 = module_0.triangle(float_0, float_0, int_0)
9 assert str_0 == "Isosceles triangle"
10
11
12def test_case_1():
13 bool_0 = True
14 str_0 = module_0.triangle(bool_0, bool_0, bool_0)
15 assert str_0 == "Equilateral triangle"
16 bool_1 = False
17 str_1 = module_0.triangle(bool_1, bool_0, bool_0)
18 assert str_1 == "Isosceles triangle"
19
20
21def test_case_2():
22 object_0 = module_1.object()
23 bool_0 = True
24 bool_1 = True
25 str_0 = module_0.triangle(bool_0, bool_1, bool_0)
26 assert str_0 == "Equilateral triangle"
27 int_0 = -2898
28 bool_2 = False
29 str_1 = module_0.triangle(bool_2, bool_2, int_0)
30 assert str_1 == "Isosceles triangle"
31 none_type_0 = None
32 str_2 = module_0.triangle(object_0, int_0, none_type_0)
33 assert str_2 == "Scalene triangle"
We can see that each test case consists of one or more invocations of the triangle function
and that there are assertions that check for the correct return value.
We can now run the generated test cases using pytest with coverage enabled
to see that indeed all code is covered:
$ pytest \
--cov=example \
--cov-branch docs/source/_static/test_example.py
Note
Pynguin uses ruff-format for formatting.
A more complex example
The above triangle example is really simple and could also be covered by a simple fuzzing tool.
Thus, we now look at a more complex example: An implementation of a Queue for int elements.
(located in docs/source/_static/queue_example.py):
1import array
2
3
4class Queue:
5 def __init__(self, size_max: int) -> None:
6 assert size_max > 0
7 self.max = size_max
8 self.head = 0
9 self.tail = 0
10 self.size = 0
11 self.data = array.array("i", range(size_max))
12
13 def empty(self) -> bool:
14 return self.size == 0
15
16 def full(self) -> bool:
17 return self.size == self.max
18
19 def enqueue(self, x: int) -> bool:
20 if self.size == self.max:
21 return False
22 self.data[self.tail] = x
23 self.size += 1
24 self.tail += 1
25 if self.tail == self.max:
26 self.tail = 0
27 return True
28
29 def dequeue(self) -> int | None:
30 if self.size == 0:
31 return None
32 x = self.data[self.head]
33 self.size -= 1
34 self.head += 1
35 if self.head == self.max:
36 self.head = 0
37 return x
Testing this queue is more complex. One needs to instantiate it, add items, etc.
Similar to the triangle example, we start Pynguin with the following command:
$ pynguin \
--project-path ./docs/source/_static/ \
--output-path /tmp/pynguin-results \
--module-name queue_example \
-v
The command yields the following output:
[09:18:31] INFO Starting Pynguin client with master-worker architecture client.py:40
INFO [Worker-37545] Worker process started (PID: 37545) worker.py:97
INFO [Worker-37545] Start Pynguin Test Generation… generator.py:141
INFO [Worker-37545] Collecting static constants from module under test generator.py:265
INFO [Worker-37545] No constants found generator.py:268
INFO [Worker-37545] Setting up runtime collection of constants generator.py:275
INFO [Worker-37545] Analyzed project to create test cluster module.py:1690
INFO [Worker-37545] Modules: 2 module.py:1691
INFO [Worker-37545] Functions: 0 module.py:1692
INFO [Worker-37545] Classes: 13 module.py:1693
INFO [Worker-37545] Using seed 1764317910386968000 generator.py:245
INFO [Worker-37545] Using strategy: Algorithm.DYNAMOSA generationalgorithmfactory.py:297
INFO [Worker-37545] Instantiated 14 fitness functions generationalgorithmfactory.py:385
INFO [Worker-37545] Using CoverageArchive generationalgorithmfactory.py:339
INFO [Worker-37545] Using selection function: Selection.RANK_SELECTION generationalgorithmfactory.py:314
INFO [Worker-37545] No stopping condition configured! generationalgorithmfactory.py:113
INFO [Worker-37545] Using fallback timeout of 600 seconds generationalgorithmfactory.py:114
INFO [Worker-37545] Using crossover function: SinglePointRelativeCrossOver generationalgorithmfactory.py:327
INFO [Worker-37545] Using ranking function: RankBasedPreferenceSorting generationalgorithmfactory.py:347
INFO [Worker-37545] Start generating test cases generator.py:606
INFO [Worker-37545] Initial Population, Coverage: 0.642857 searchobserver.py:75
INFO [Worker-37545] Local search complete, the coverage hasn't changed dynamosaalgorithm.py:152
INFO [Worker-37545] Iteration: 1, Coverage: 0.857143 searchobserver.py:81
INFO [Worker-37545] Local search complete, the coverage hasn't changed dynamosaalgorithm.py:152
INFO [Worker-37545] Iteration: 2, Coverage: 0.928571 searchobserver.py:81
INFO [Worker-37545] Local search complete, the coverage hasn't changed dynamosaalgorithm.py:152
INFO [Worker-37545] Iteration: 3, Coverage: 0.928571 searchobserver.py:81
INFO [Worker-37545] Local search complete, the coverage hasn't changed dynamosaalgorithm.py:152
INFO [Worker-37545] Iteration: 4, Coverage: 1.000000 searchobserver.py:81
INFO [Worker-37545] Algorithm stopped before using all resources. generator.py:609
INFO [Worker-37545] Stop generating test cases generator.py:614
INFO [Worker-37545] Minimizing test cases generator.py:623
INFO [Worker-37545] Removed 28 statement(s) from test casesusing CASE minimization generator.py:777
INFO [Worker-37545] Coverage after minimization is the same as before: [1.0] generator.py:716
INFO [Worker-37545] Start generating assertions generator.py:898
INFO [Worker-37545] Setup mutation generator generator.py:871
INFO [Worker-37545] Import module queue_example generator.py:874
INFO [Worker-37545] Build AST for queue_example generator.py:877
INFO [Worker-37545] Mutate module queue_example generator.py:881
INFO [Worker-37545] Generated 31 mutants generator.py:891
[09:18:32] INFO [Worker-37545] Running tests on mutant 1/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 2/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 3/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 4/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 5/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 6/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 7/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 8/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 9/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 10/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 11/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 12/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 13/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 14/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 15/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 16/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 17/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 18/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 19/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 20/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 21/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 22/31 assertiongenerator.py:276
INFO [Worker-37545] Skipping mutant 23/31 because it created an invalid module assertiongenerator.py:269
INFO [Worker-37545] Running tests on mutant 24/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 25/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 26/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 27/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 28/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 29/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 30/31 assertiongenerator.py:276
INFO [Worker-37545] Running tests on mutant 31/31 assertiongenerator.py:276
INFO [Worker-37545] Mutant 0 killed by Test(s): 2, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 1 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 2 killed by Test(s): 4, 5 assertiongenerator.py:378
INFO [Worker-37545] Mutant 3 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 4 killed by Test(s): 2, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 5 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 6 killed by Test(s): 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 7 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 8 killed by Test(s): 0, 2, 3, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 9 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 10 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 11 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 12 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 13 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 14 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 15 killed by Test(s): 2, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 16 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 18 killed by Test(s): 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 19 killed by Test(s): 4, 5 assertiongenerator.py:378
INFO [Worker-37545] Mutant 20 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 23 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 24 killed by Test(s): 0, 1, 2, 3, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 25 killed by Test(s): 0, 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 26 killed by Test(s): 2, 3, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 27 killed by Test(s): 2, 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 28 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Mutant 29 killed by Test(s): 4, 5, 6 assertiongenerator.py:378
INFO [Worker-37545] Mutant 30 killed by Test(s): 4 assertiongenerator.py:378
INFO [Worker-37545] Number of Surviving Mutant(s): 3 (Mutants: 17, 21, 22) assertiongenerator.py:390
INFO [Worker-37545] Calculating resulting FinalBranchCoverage generator.py:534
INFO [Worker-37545] Written 7 test cases to /private/tmp/pynguin-results/test_queue_example.py generator.py:1007
INFO [Worker-37545] Writing statistics stats.py:368
INFO [Worker-37545] Stop Pynguin Test Generation… generator.py:146
INFO [Worker-37545] Worker completed task: test_gen_1764317911.477082 worker.py:110
[09:18:32] INFO Received result for task test_gen_1764317911.477082: WorkerReturnCode.OK master.py:133
INFO Stopping master-worker system client.py:44
INFO Master-worker system stopped client.py:46
We can see that the DYNAMOSA algorithm had to perform four iterations to fully cover
the Queue example.
We can also see that Pynguin generated seven test cases:
1# Test cases automatically generated by Pynguin (https://www.pynguin.eu).
2import pytest
3import queue_example as module_0
4
5
6def test_case_0():
7 bool_0 = True
8 queue_0 = module_0.Queue(bool_0)
9 assert (
10 f"{type(queue_0).__module__}.{type(queue_0).__qualname__}"
11 == "queue_example.Queue"
12 )
13 assert queue_0.max is True
14 assert queue_0.head == 0
15 assert queue_0.tail == 0
16 assert queue_0.size == 0
17 assert (
18 f"{type(queue_0.data).__module__}.{type(queue_0.data).__qualname__}"
19 == "array.array"
20 )
21 assert len(queue_0.data) == 1
22 queue_0.dequeue()
23 queue_1 = module_0.Queue(bool_0)
24 assert queue_1.head == 0
25 assert queue_1.tail == 0
26 assert queue_1.size == 0
27 bool_1 = queue_1.empty()
28 assert bool_1 is True
29 bool_2 = False
30 with pytest.raises(AssertionError):
31 module_0.Queue(bool_2)
32
33
34def test_case_1():
35 bool_0 = False
36 with pytest.raises(AssertionError):
37 module_0.Queue(bool_0)
38
39
40def test_case_2():
41 bool_0 = True
42 bool_1 = True
43 queue_0 = module_0.Queue(bool_1)
44 assert (
45 f"{type(queue_0).__module__}.{type(queue_0).__qualname__}"
46 == "queue_example.Queue"
47 )
48 assert queue_0.max is True
49 assert queue_0.head == 0
50 assert queue_0.tail == 0
51 assert queue_0.size == 0
52 assert (
53 f"{type(queue_0.data).__module__}.{type(queue_0.data).__qualname__}"
54 == "array.array"
55 )
56 assert len(queue_0.data) == 1
57 bool_2 = queue_0.empty()
58 assert bool_2 is True
59 bool_3 = queue_0.full()
60 assert bool_3 is False
61 bool_4 = queue_0.enqueue(bool_0)
62 assert bool_4 is True
63 assert queue_0.size == 1
64 bool_5 = False
65 with pytest.raises(AssertionError):
66 module_0.Queue(bool_5)
67
68
69def test_case_3():
70 bool_0 = False
71 bool_1 = True
72 queue_0 = module_0.Queue(bool_1)
73 assert (
74 f"{type(queue_0).__module__}.{type(queue_0).__qualname__}"
75 == "queue_example.Queue"
76 )
77 assert queue_0.max is True
78 assert queue_0.head == 0
79 assert queue_0.tail == 0
80 assert queue_0.size == 0
81 assert (
82 f"{type(queue_0.data).__module__}.{type(queue_0.data).__qualname__}"
83 == "array.array"
84 )
85 assert len(queue_0.data) == 1
86 bool_2 = queue_0.empty()
87 assert bool_2 is True
88 bool_3 = queue_0.full()
89 assert bool_3 is False
90 with pytest.raises(AssertionError):
91 module_0.Queue(bool_0)
92
93
94def test_case_4():
95 int_0 = 922
96 queue_0 = module_0.Queue(int_0)
97 assert (
98 f"{type(queue_0).__module__}.{type(queue_0).__qualname__}"
99 == "queue_example.Queue"
100 )
101 assert queue_0.max == 922
102 assert queue_0.head == 0
103 assert queue_0.tail == 0
104 assert queue_0.size == 0
105 assert (
106 f"{type(queue_0.data).__module__}.{type(queue_0.data).__qualname__}"
107 == "array.array"
108 )
109 assert len(queue_0.data) == 922
110 queue_0.dequeue()
111 bool_0 = queue_0.empty()
112 assert bool_0 is True
113 bool_1 = queue_0.enqueue(int_0)
114 assert bool_1 is True
115 assert queue_0.tail == 1
116 assert queue_0.size == 1
117 var_0 = queue_0.dequeue()
118 assert var_0 == 922
119 assert queue_0.head == 1
120 assert queue_0.size == 0
121 bool_2 = queue_0.full()
122 assert bool_2 is False
123
124
125def test_case_5():
126 bool_0 = True
127 queue_0 = module_0.Queue(bool_0)
128 assert (
129 f"{type(queue_0).__module__}.{type(queue_0).__qualname__}"
130 == "queue_example.Queue"
131 )
132 assert queue_0.max is True
133 assert queue_0.head == 0
134 assert queue_0.tail == 0
135 assert queue_0.size == 0
136 assert (
137 f"{type(queue_0.data).__module__}.{type(queue_0.data).__qualname__}"
138 == "array.array"
139 )
140 assert len(queue_0.data) == 1
141 bool_1 = queue_0.empty()
142 assert bool_1 is True
143 bool_2 = queue_0.enqueue(bool_0)
144 assert bool_2 is True
145 assert queue_0.size == 1
146 var_0 = queue_0.dequeue()
147 assert var_0 == 1
148 assert queue_0.size == 0
149 bool_3 = queue_0.full()
150 assert bool_3 is False
151
152
153def test_case_6():
154 bool_0 = True
155 bool_1 = True
156 queue_0 = module_0.Queue(bool_1)
157 assert (
158 f"{type(queue_0).__module__}.{type(queue_0).__qualname__}"
159 == "queue_example.Queue"
160 )
161 assert queue_0.max is True
162 assert queue_0.head == 0
163 assert queue_0.tail == 0
164 assert queue_0.size == 0
165 assert (
166 f"{type(queue_0.data).__module__}.{type(queue_0.data).__qualname__}"
167 == "array.array"
168 )
169 assert len(queue_0.data) == 1
170 queue_0.dequeue()
171 bool_2 = queue_0.empty()
172 assert bool_2 is True
173 bool_3 = queue_0.full()
174 assert bool_3 is False
175 bool_4 = queue_0.enqueue(bool_0)
176 assert bool_4 is True
177 assert queue_0.size == 1
178 bool_5 = queue_0.enqueue(bool_3)
179 assert bool_5 is False
180 int_0 = 0
181 with pytest.raises(AssertionError):
182 module_0.Queue(int_0)
When running the generated test cases with coverage enabled, we see once more that all code is covered:
$ pytest \
--cov=queue_example \
--cov-branch docs/source/_static/test_queue_example.py
Note
Generated test cases may contain redundant assertions. Minimising these is open for a future release of Pynguin.
Logging
Pynguin provides the ability to write logging output to a log file in addition to STDOUT.
This can be configured using the --log-file parameter:
$ pynguin \
--project-path ./docs/source/_static/ \
--output-path /tmp/pynguin-results \
--module-name example \
-v \
--log-file /tmp/pynguin-log.txt
This will write all log messages to the specified file, making it easier to analyze the test generation process or troubleshoot issues without cluttering the console output.