Package: laziest
Generator of test_*.py files for your Python code.
Package that trying generate unit tests for you.In step of testing idea :)From code like this:defone_condition_custom_exception_and_return_binary_op_and_key(arg1,arg2,arg3):ifarg1=='1':raiseCustomException('we hate 1')elifarg2[3]>2:print(f'{arg2[3]}more when 2')var=1alias=varreturnarg1*arg2[3]+arg3['number'],var*arg1*alias-2Laziest create such test:deftest_one_condition_custom_exception_and_return_binary_op_and_key(capsys):assertone_condition_custom_exception_and_return_binary_op_and_key(arg1=-720,arg2=[1.14,5.79,0.67,-984],arg3={"number":1})==(708481,-722)withpytest.raises(CustomException):#  error message: we hate 1one_condition_custom_exception_and_return_binary_op_and_key(arg1="1",arg2=[1.14,5.79,0.67,2.05],arg3={"number":1})one_condition_custom_exception_and_return_binary_op_and_key(arg1=166,arg2=[1.14,5.79,0.67,935],arg3={"number":1})captured=capsys.readouterr()assertcaptured.out=="935 more when 2\n"Introducing>>> Some slides with idea <<<Hi!If you was hope to see information of production-ready solution - sorry, no.This is just a try to create POC of idea to generate unit tests based on AST.In source code you can see a mess with very strange constractions and a lot of ‘TODO’s
this is only because pack in very active development phase and I forget idea to plan it first and then develop,
because all my ‘plans’ crashed after adding support of 4-5 AST nodes and their combinationsYou can think about this project like a something ‘study’:
I invistigate metaprogramming and AST in idea generate unittests from source code :)And you can join me in this investigation if you interesting in this too!
So if you want to know how far this idea can go - join me in this interesting and fun road (check section Contributing)Little bit of historyThis is a 3rd version of package implementation, before using a mix of work with AST and tokenisation (current state)
I tried different ways:inspect and other tools with live objectsonly syntax and tokens + regexesand the current state with AST.I also checked packages that already exist, but they produce different result (but maybe you will be interesting
more in them, when in this project in-work, so I attach links, if you don’t know yet this packages - check them):Installation:pip install laziestUsage:lazy/path/to/python/code/filesFor example:lazy/home/yourUser/laziest/tests/code_sample/done/conditions.pyIt will generate test file in directory:/home/yourUser/laziest/tests/test_conditions.pyRun tests with ‘pytest’ to check that they are valid:pytest/home/yourUser/laziest/tests/functional/test_primitive_code.pyFlag -dIf you want to generate empty tests in case if code not supported by generator yet, you can use flag ‘-d’.
Output will be - generated modules for all functions, but without asserts, in body of function you will see a
comment with error and ‘pass’.For example, you have a code with logic, that not supported yet by generator, for example:defstring_format_named_three_args(arg1,arg2,arg3):return'{first}this is{name}!{last}'.format(name=arg1,first=arg2,last=arg3)If you run lazy with flag ‘-d’ - you will have success test generation and in test module you will see for this function test:deftest_string_format_named_three_args():# string indices must be integers# Traceback (most recent call last):#  File "/Users/jvolkova/laziest/laziest/functions.py", line 163, in test_creation#    func_definition, func_name, func_data, class_, class_method_type)# TypeError: string indices must be integers#passTestsYou can run laziest tests with tox and check output.ContributingPull requests are welcome.What and how you can contribute?1. Ideas, comment to logic, some architecture and solutions plans - this is very welcome, because I works alone in
this thing and I can be very subjective and make wrong solutions.Cases in laziest/tests/code_sample/todo.How create case:A. Use like a sample:
laziest/tests/code_sample/done/primitive_code.pyB. You need to add operations from simplest (if they was not covered in different cases) to most complicated.
So, if you want add into code cases this function:deffunction_with_vars_operations(new_name,use_data,validate_len=True):ifvalidate_lenandlen(new_name)>15:raiseException("Impossible to set so long name. Lenght of the name must be < 15 symbols)user_data['name']=new_namereturnuser_dataYou must to be sure, that already supported (or covered by cases):Functions with argumentsif statementsif statements with 2 or more conditions, because here we see ‘validate_len’ - first condition and ‘len(new_name) > 15’ - second conditionyou need check that conditions like ‘if something’ are supported and covered or create cases for that separate. Why does it matter? Because, ‘if validate_len’ under the hood mean ‘validate_len != 0, validate_len != [], validate_len != () or any other empty container’correct work with default values for ‘validate_len=True’ - so need 2 assert, test with default value and withoutand etc.D. Try to split your result on blocks, if you don’t see in code samples something that already ready.
You also can just run generator on separated functions to see does generator cover test case correct or not.For current example ‘separated’ functions can be at least (because 1 and 2 already supported):
1.deffunction_with_multiple_if_conditions(new_name,use_data,validate_len):ifvalidate_len!=0andlen(new_name)>15:raiseException("Impossible to set so long name. Lenght of the name must be < 15 symbols)returnuser_datanow same but with default valuedeffunction_with_default_value(new_name,use_data,validate_len=True):ifvalidate_len!=False:raiseException("Impossible to set so long name. Lenght of the name must be < 15 symbols)returnuser_datanow same but without ‘!=’deffunction_with_if_exist(new_name,use_data,validate_len=True):ifvalidate_len:raiseException("Impossible to set so long name. Lenght of the name must be < 15 symbols)returnuser_dataYou can change places of 2 and 3 - this is not matter.and at the enddeffunction_with_vars_operations(new_name,use_data,validate_len=True):ifvalidate_lenandlen(new_name)>15:raiseException("Impossible to set so long name. Lenght of the name must be < 15 symbols)user_data['name']=new_namereturnuser_dataIf you added some features in code, please make sure to update tests as appropriate:This is mean you add in laziest/tests/code_sample/done construction that successful covered by generator and tests that was generated also passed.LicenseThis project is licensed under the Apache License - see theLICENSEfile for details