Closed Alexander-Serov closed 1 year ago
Thanks for your feedback. This problem is related to the library that we use for bytecode instrumentation, as Pynguin only works with a certain version of that library. Can you try to manually install bytecode = 0.13
in your virtual env? That should fix this problem.
Thanks for the fast answer @Wooza!
This did allow me to advance further indeed. However, this simple example still fails (supposedly, after test generation is finished and while trying to interpret variable s
in the definition?):
> pynguin \
--output-path ./pynguin --project-path . \
--module-name pynguin-example \
-v
[12:39:20] INFO Start Pynguin Test Generation… generator.py:110
INFO Collecting static constants from module under test generator.py:209
INFO No constants found generator.py:212
INFO Setting up runtime collection of constants generator.py:221
INFO Analyzed project to create test cluster module.py:1186
INFO Modules: 1 module.py:1187
INFO Functions: 1 module.py:1188
INFO Classes: 11 module.py:1189
INFO Using seed 1672745959264509000 generator.py:195
INFO Using strategy: Algorithm.DYNAMOSA generationalgorithmfactory.py:272
INFO Instantiated 3 fitness functions generationalgorithmfactory.py:363
INFO Using CoverageArchive generationalgorithmfactory.py:316
INFO Using selection function: Selection.TOURNAMENT_SELECTION generationalgorithmfactory.py:291
INFO No stopping condition configured! generationalgorithmfactory.py:95
INFO Using fallback timeout of 600 seconds generationalgorithmfactory.py:96
INFO Using crossover function: SinglePointRelativeCrossOver generationalgorithmfactory.py:304
INFO Using ranking function: RankBasedPreferenceSorting generationalgorithmfactory.py:324
INFO Start generating test cases generator.py:507
INFO Initial Population, Coverage: 0.666667 searchobserver.py:66
INFO Iteration: 1, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 2, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 3, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 4, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 5, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 6, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 7, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 8, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 9, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 10, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 11, Coverage: 0.666667 searchobserver.py:70
[12:39:21] INFO Iteration: 12, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 13, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 14, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 15, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 16, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 17, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 18, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 19, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 20, Coverage: 0.666667 searchobserver.py:70
INFO Iteration: 21, Coverage: 1.000000 searchobserver.py:70
INFO Algorithm stopped before using all resources. generator.py:510
INFO Stop generating test cases generator.py:515
INFO Start generating assertions generator.py:588
INFO Setup mutation controller mutationadapter.py:68
INFO Build AST for pynguin-example mutationadapter.py:54
INFO Mutate module pynguin-example mutationadapter.py:56
INFO Generated 4 mutants mutationadapter.py:64
INFO Running tests on mutant 1/4 assertiongenerator.py:290
INFO Running tests on mutant 2/4 assertiongenerator.py:290
INFO Running tests on mutant 3/4 assertiongenerator.py:290
INFO Running tests on mutant 4/4 assertiongenerator.py:290
INFO Mutant 0 killed by Test(s): 0, 1 assertiongenerator.py:369
INFO Mutant 1 killed by Test(s): 0, 1 assertiongenerator.py:369
INFO Mutant 2 killed by Test(s): 1 assertiongenerator.py:369
INFO Mutant 3 killed by Test(s): 0, 1 assertiongenerator.py:369
INFO Number of Surviving Mutant(s): 0 (Mutants: ) assertiongenerator.py:381
INFO Calculating resulting FinalBranchCoverage generator.py:428
INFO Stop Pynguin Test Generation… generator.py:113
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/user/miniforge3/envs/pynguin/bin/pynguin:8 in <module> │
│ │
│ 5 from pynguin.cli import main │
│ 6 if __name__ == '__main__': │
│ 7 │ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) │
│ ❱ 8 │ sys.exit(main()) │
│ 9 │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/pynguin/cli.py:190 in main │
│ │
│ 187 │ set_configuration(parsed.config) │
│ 188 │ if console is not None: │
│ 189 │ │ with console.status("Running Pynguin..."): │
│ ❱ 190 │ │ │ return run_pynguin().value │
│ 191 │ else: │
│ 192 │ │ return run_pynguin().value │
│ 193 │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/pynguin/generator.py:111 in │
│ run_pynguin │
│ │
│ 108 │ """ │
│ 109 │ try: │
│ 110 │ │ _LOGGER.info("Start Pynguin Test Generation…") │
│ ❱ 111 │ │ return _run() │
│ 112 │ finally: │
│ 113 │ │ _LOGGER.info("Stop Pynguin Test Generation…") │
│ 114 │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/pynguin/generator.py:533 in │
│ _run │
│ │
│ 530 │ │ config.configuration.test_case_output.export_strategy │
│ 531 │ │ == config.ExportStrategy.PY_TEST │
│ 532 │ ): │
│ ❱ 533 │ │ _export_chromosome(generation_result) │
│ 534 │ │
│ 535 │ if config.configuration.statistics_output.create_coverage_report: │
│ 536 │ │ coverage_report = get_coverage_report( │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/pynguin/generator.py:690 in │
│ _export_chromosome │
│ │
│ 687 │ ) │
│ 688 │ export_visitor = export.PyTestChromosomeToAstVisitor() │
│ 689 │ chromosome.accept(export_visitor) │
│ ❱ 690 │ export.save_module_to_file( │
│ 691 │ │ export_visitor.to_module(), │
│ 692 │ │ target_file, │
│ 693 │ │ config.configuration.test_case_output.format_with_black, │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/pynguin/generation/export.py: │
│ 194 in save_module_to_file │
│ │
│ 191 │ │ │ # so we only import it if we need it. │
│ 192 │ │ │ import black # pylint:disable=import-outside-toplevel │
│ 193 │ │ │ │
│ ❱ 194 │ │ │ output = black.format_str(output, mode=black.FileMode()) │
│ 195 │ │ file.write(output) │
│ 196 │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/black/__init__.py:1073 in │
│ format_str │
│ │
│ 1070 │ │ hey │
│ 1071 │ │
│ 1072 │ """ │
│ ❱ 1073 │ dst_contents = _format_str_once(src_contents, mode=mode) │
│ 1074 │ # Forced second pass to work around optional trailing commas (becoming │
│ 1075 │ # forced trailing commas on pass 2) interacting differently with optional │
│ 1076 │ # parentheses. Admittedly ugly. │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/black/__init__.py:1083 in │
│ _format_str_once │
│ │
│ 1080 │
│ 1081 │
│ 1082 def _format_str_once(src_contents: str, *, mode: Mode) -> str: │
│ ❱ 1083 │ src_node = lib2to3_parse(src_contents.lstrip(), mode.target_versions) │
│ 1084 │ dst_blocks: List[LinesBlock] = [] │
│ 1085 │ if mode.target_versions: │
│ 1086 │ │ versions = mode.target_versions │
│ │
│ /Users/user/miniforge3/envs/pynguin/lib/python3.10/site-packages/black/parsing.py:127 in │
│ lib2to3_parse │
│ │
│ 124 │ │ │ msg = f"{original_msg}\n{PY2_HINT}" │
│ 125 │ │ │ raise InvalidInput(msg) from None │
│ 126 │ │ │
│ ❱ 127 │ │ raise exc from None │
│ 128 │ │
│ 129 │ if isinstance(result, Leaf): │
│ 130 │ │ result = Node(syms.file_input, [result]) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
InvalidInput: Cannot parse: 2:14: import pynguin-example as module_0
(Location 2:14 is the s
symbol in the def)
Pynguin tries to format the generated tests using black. I think location 2:14
refers to the -
in the string import pynguin-example as module_0
. It seems like you tried to apply Pynguin on a module called on pynguin-example
. AFAIK, module names (i.e. things that can be imported in Python) are not allowed to contain a -
in their name, which is why black fails to parse the generated tests. Renaming your file accordingly should fix that problem as well.
Oh, nice catch, thank you! Maybe add a clearer message for when the formatting fails, but it solves my issue, thanks!
And one more question, not related @Wooza,
Would you know what the message AttributeError: 'NoneType' object has no attribute 'NDArray'
could mean? I am trying to create tests for code including pd.DataFrames
. I am guessing this also means that testing code including pandas DataFrames is not currently supported?
Consider a simple function:
Pynguin
test generation fails on it with an unclearAttributeError
message:From what I understand, this functionality is still in development, which is fine since it's a free project. :) But perhaps, at least give the user a clearer message? I was kind of confused by the message
AttributeError: IN
.And it also seems to me that
in
is a very popular operator, so please consider it a feature request. :)Other than that, thanks and keep up the good job!