{ "info": { "author": "Paul Kovtun", "author_email": "trademet@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "Sloth Test is a Python library that automatically create unit tests based on previous real-life cases to prevent regression bugs.\n1. You will connect the Sloth Test library to your project and run the project for execution the typical routine. \n2. The Sloth collect the internal states of the classes, methods and functions you use in your project and you pointed the Sloth to watch at. It will record all possible incomes and outcomes of each method for each run\n3. After it collects enough data, the library dumps the collected data to a file\n4. For each recorded run in this file, Sloth Test will automatically create a particular unit test, with the particular state of the class, the particular recorded serialized incomes and an assertion of outcomes for this method.\nThe result is a collection of typical pytest unit tests that can be executed as a part of testing routine. \n5. For each modification of this method you can run these created test cases to check if the method doesn\u00e2\u20ac\u2122t get new bugs and implements the business logic it supposed to have.\n------------------------------------------------------------------\n\nSuppose that we have a critical and sophisticated method that is a part of our ETL process (pd_table is a pandas table) :\n\n```\ndef do_useful_stuff(pd_table=None, a=0, b=0):\n\n for i, row in pd_table.iterrows():\n pd_table['value'][i] = row['value'] * a + b\n\n return pd_table\n```\n\nLet\u00e2\u20ac\u2122s show some run examples that we will implement via other method as the part of our ETL process:\n\n```\ndef run():\n\n tables = {\n 'table1': pd.DataFrame([{'column': 1, 'value': 1},\n {'column': 2, 'value': 2},\n {'column': 3, 'value': 4}]),\n\n 'table2': pd.DataFrame([{'column': 1, 'value': 1},\n {'column': 2, 'value': 2},\n {'column': 3, 'value': 4}]),\n\n 'table3': pd.DataFrame([{'value': 1},\n {'value': 2},\n {'value': 4}]),\n\n 'table4': pd.DataFrame([{'value': 1000},\n {'value': 10}]),\n }\n\n for t_name, pd_table in tables.items():\n print(\"Table {name}: \\n {table} \\n\".\n format(name=t_name, table=str(do_useful_stuff(pd_table=pd_table, a=2, b=3))))\n\nif __name__ == '__main__':\n run()\n```\n\nthe results are:\n\n```\nTable table1: \n column value\n0 1 5\n1 2 7\n2 3 11 \n\nTable table2: \n column value\n0 1 5\n1 2 7\n2 3 11 \n\nTable table3: \n value\n0 5\n1 7\n2 11 \n\nTable table4: \n value\n0 2003\n1 23\n```\n\nOk. Next, we need to be sure that this method will implement the business logic it supposed to implement. To do that, we need to write manually a bunch of pytests for this method for various incomes and outcomes (perhaps 100+ tests for different variants of tables). Or use a Sloth Test library to do it for us automatically.\n\n1. Install Sloth Test:\n\n```pip install slothtest -U```\n\n2. The first step - we need to import a @watchme() decorator from a slothtest library. This decorator should be used on the target method need the Sloth to watch at. Let\u00e2\u20ac\u2122s add it to our function:\n\n```\nfrom slothtest import watchme\n\n@watchme()\ndef do_useful_stuff(pd_table=None, a=0, b=0):\n\n for i, row in pd_table.iterrows():\n pd_table['value'][i] = row['value'] * a + b\n\n```\n\n3. We need to point a sloth watcher where it should start its watching process and where it should stop to watch. It can be an entry and exits points of an application, or logic start and stop track inside our app. For our tiny app it\u00e2\u20ac\u2122s a run method, so our code will look like:\n\n```\nif __name__ == '__main__':\n slothwatcher.start()\n run()\n slothwatcher.stop()\n\n```\n\n.. and that\u00e2\u20ac\u2122s all!\n\n4. Now, let\u00e2\u20ac\u2122s run our app as usual, and let the Sloth to watch our process run. After a run, in a folder with our example, a new zip-file appears with a filename in digits (it\u00e2\u20ac\u2122s a timestamp) and a dump of our runs inside this zip file\nThe zip-dump creates after a sloth is stopped, or it recorded a certain amount of runs for all the methods it watched. An amount of runs we can set via SlothConfig class\n\n```\nfrom slothtest import SlothConfig\nSlothConfig.DUMP_ITER_COUNT = 200\n\n```\n\n5. At this point, we have a dump file. Now, for further development purpose we need to get a typical pytest unit tests. We can create that from our dump file, using a sloth translator:\n\n```python -m slothtest.sloth_xml_converter -p o:\\work\\slothexample -d o:\\work\\slothexample 1549134821.zip```\n\nwhere -p is the key to a directory where we will put a path to our project, and -d is the key to a directory where the result pytest files will be created\n5. The result of the conversion are two files: \n1) test_sloth_1549134821.py and 2) sloth_test_parval_1549134821.py\nThe first one is a basic pytest collection for each run of our watched function:\n\n\n```\nimport sloth_test_parval_1549134821 as sl \n\ndef test_do_useful_stuff_1(): \n from themethod import do_useful_stuff\n\n try:\n run_result = do_useful_stuff(pd_table=sl.val_do_useful_stuff_1_pd_table, a=sl.val_do_useful_stuff_1_a, b=sl.val_do_useful_stuff_1_b, ) \n except Exception as e:\n run_result = e\n\n test_result = sl.res_do_useful_stuff_1_ret_0 \n assert(type(run_result) == type(test_result))\n assert(run_result.equals(test_result))\n\n\ndef test_do_useful_stuff_2(): \n from themethod import do_useful_stuff\n\n try:\n run_result = do_useful_stuff(pd_table=sl.val_do_useful_stuff_2_pd_table, a=sl.val_do_useful_stuff_2_a, b=sl.val_do_useful_stuff_2_b, ) \n except Exception as e:\n run_result = e\n\n test_result = sl.res_do_useful_stuff_2_ret_0 \n assert(type(run_result) == type(test_result))\n assert(run_result.equals(test_result))\n\u00e2\u20ac\u00a6\n\n\n```\n\nAnd the second one is the serialized (or raw values if they are a primitive type) income and outcome values for each run of the method (4 cases):\n\n```\nimport codecs\nimport io\nimport joblib\n\n\n# ===== 1: do_useful_stuff@themethod\n\nvar_stream = io.BytesIO()\nvar_stream_str = codecs.decode('gANdWIu\u00e2\u20ac\u00a6'.encode(),\"base64\")\n\nvar_stream.write(var_stream_str)\nvar_stream.seek(0)\nval_do_useful_stuff_1_pd_table = joblib.load(var_stream)\n\nval_do_useful_stuff_1_a = 2\n\nval_do_useful_stuff_1_b = 3\n\nres_stream = io.BytesIO()\nres_stream_str = codecs.decode('gANdWIu\u00e2\u20ac\u00a6\\n'.encode(),\"base64\")\nres_stream.write(res_stream_str)\nres_stream.seek(0)\nres_do_useful_stuff_1_ret_0 = joblib.load(res_stream)\n\u00e2\u20ac\u00a6\n\n```\n\n6. Now we can run our testing routine with pytest as usual:\n\n\n```\npython -m pytest test_sloth_1549134821.py\n\n================================================= test session starts =================================================\nplatform win32 -- Python 3.7.0, pytest-4.1.1, py-1.7.0, pluggy-0.8.1\nrootdir: o:\\work\\slothexample, inifile:\nplugins: remotedata-0.3.1, openfiles-0.3.2, doctestplus-0.2.0, arraydiff-0.3\ncollected 4 items\n\ntest_sloth_1549134821.py .... [100%]\n\n======================================== 4 passed, 2 warnings in 0.34 seconds =========================================\n\n```\n\nAnd that\u00e2\u20ac\u2122s all. Easy! \n\nThis approach to generate unit tests automatically can be extrapolated for as many cases as you need if your methods and classes are serializable and if you have enough space for data dumps\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/elegantwist/slothtest", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "slothtest", "package_url": "https://pypi.org/project/slothtest/", "platform": "", "project_url": "https://pypi.org/project/slothtest/", "project_urls": { "Homepage": "https://github.com/elegantwist/slothtest" }, "release_url": "https://pypi.org/project/slothtest/0.0.4/", "requires_dist": [ "joblib" ], "requires_python": "", "summary": "Sloth Test: An Automatic Unit Test Generator", "version": "0.0.4" }, "last_serial": 4772971, "releases": { "0.0.2": [ { "comment_text": "", "digests": { "md5": "9cab98bdc197c3141c0eb862a78f5ffe", "sha256": "e5ebfd6d790fc32f68448d424aa4e3cccf67f268460b664579911c1ab5440d17" }, "downloads": -1, "filename": "slothtest-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "9cab98bdc197c3141c0eb862a78f5ffe", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19167, "upload_time": "2019-02-02T10:04:41", "url": "https://files.pythonhosted.org/packages/c8/48/7bf2cbd6646b65776376a4a66ef638a5e54227303a3e1231208fb53a5c8d/slothtest-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1da11da07eaff50ddad2da857cc60214", "sha256": "93d6efc673dc06b181a33736186976cd60be5606329f7b9daaf956ed026422a3" }, "downloads": -1, "filename": "slothtest-0.0.2.tar.gz", "has_sig": false, "md5_digest": "1da11da07eaff50ddad2da857cc60214", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8193, "upload_time": "2019-02-02T10:04:42", "url": "https://files.pythonhosted.org/packages/5c/61/458a9c5eda7c04a11904400f1fa91bf2242f97532f19fb5c78416c10a646/slothtest-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "54f82955bb759f05a670e1d036ca0191", "sha256": "aab27248480b5e39ab65fd4f53f61c42a1c754cdc667f23e6fc250a7d313c4c7" }, "downloads": -1, "filename": "slothtest-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "54f82955bb759f05a670e1d036ca0191", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19483, "upload_time": "2019-02-02T15:37:45", "url": "https://files.pythonhosted.org/packages/e2/4a/3e8e923dd576a4b85fd350ae5d9533155c80b42e95f3f019266430464fbc/slothtest-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b1bceaaafd837fa6cf1a404262a6cd8b", "sha256": "86e82e52b24cc5f427acc98395726260f0c0196f34a4cb86d50caeb3d1be3806" }, "downloads": -1, "filename": "slothtest-0.0.3.tar.gz", "has_sig": false, "md5_digest": "b1bceaaafd837fa6cf1a404262a6cd8b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8309, "upload_time": "2019-02-02T15:37:46", "url": "https://files.pythonhosted.org/packages/2b/55/ceaf563bc1417efb581aaa0996b91c0afb5be4b04e909d717aa05d522b76/slothtest-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "5298ed2fd113ebd1755d0b3e9b08daf0", "sha256": "5b3f51a0068e14fe71c20a8f297f6341a2746c8128991913f90ec782581a4d11" }, "downloads": -1, "filename": "slothtest-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "5298ed2fd113ebd1755d0b3e9b08daf0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 21987, "upload_time": "2019-02-02T19:56:42", "url": "https://files.pythonhosted.org/packages/e7/e3/cbf476498ac195d6b985a3666d3b132528806cd2fba061d2c0663dd39ca9/slothtest-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "75ae28c4c28506b6dba350c98430208b", "sha256": "fca1ff615a2cba0c15c7e81200435a804de2a9e0342564ff983107867304306c" }, "downloads": -1, "filename": "slothtest-0.0.4.tar.gz", "has_sig": false, "md5_digest": "75ae28c4c28506b6dba350c98430208b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13523, "upload_time": "2019-02-02T19:56:44", "url": "https://files.pythonhosted.org/packages/7b/a5/883c409f72499701b055ff4f3b7c6fd7ae637f7867031b806f0fe9567ebf/slothtest-0.0.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5298ed2fd113ebd1755d0b3e9b08daf0", "sha256": "5b3f51a0068e14fe71c20a8f297f6341a2746c8128991913f90ec782581a4d11" }, "downloads": -1, "filename": "slothtest-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "5298ed2fd113ebd1755d0b3e9b08daf0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 21987, "upload_time": "2019-02-02T19:56:42", "url": "https://files.pythonhosted.org/packages/e7/e3/cbf476498ac195d6b985a3666d3b132528806cd2fba061d2c0663dd39ca9/slothtest-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "75ae28c4c28506b6dba350c98430208b", "sha256": "fca1ff615a2cba0c15c7e81200435a804de2a9e0342564ff983107867304306c" }, "downloads": -1, "filename": "slothtest-0.0.4.tar.gz", "has_sig": false, "md5_digest": "75ae28c4c28506b6dba350c98430208b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13523, "upload_time": "2019-02-02T19:56:44", "url": "https://files.pythonhosted.org/packages/7b/a5/883c409f72499701b055ff4f3b7c6fd7ae637f7867031b806f0fe9567ebf/slothtest-0.0.4.tar.gz" } ] }