# Python Student Testing Framework
## Contents
- [Introduction](#introduction)
- [Features](#features)
- [Installation](#installation)
- [Contributing](#contributing)
- [License](#license)
- [Contact](#contact)
- [How to use](#how-to-use)
- [Extension for Visual Studio Code](#extension-for-visual-studio-code)
## Introduction
Welcome to the Python Student Testing Framework! This README provides a brief overview of what the framework is and how to use it. The framework is designed for instructors and TAs to easily test and grade students Python code.
## Features
- Automated testing of students' code against a set of test cases
- Support for multiple test cases and multiple functions
- Ability to define custom tests and assertions
- Clear and detailed feedback for students on test results
- Display HTML report
## Installation
To use the Python Student Testing Framework, you will need to have Python installed on your machine. Then, simply clone the repository or install with `pip install school-grader`
## Contributing
The Python Student Testing Framework is an open-source project and contributions are welcome.
## License
The Python Student Testing Framework is released under the MIT license. See the LICENSE file for more information.
## Contact
If you have any questions or issues, please create a GitHub issue or reach out to the project maintainers at marcolivier.derouin@poulet-frit.com
## How to use
Let's say you have given an assignment to your students.
### assignment1.py
```python
words = input("Please enter a list of words separated by spaces: ").split(" ")
palindrome_words = []
non_palindrome_words = []
for word in words:
lowercase_word = word.lower()
if lowercase_word == lowercase_word[::-1]:
palindrome_words.append(word)
else:
non_palindrome_words.append(word)
print("Palindrome words:" + " ".join(palindrome_words))
print("Non-palindrome words:" + " ".join(non_palindrome_words))
```
You can write test case for this assignment using the following code.
```python
from school_grader import FileTestCase, run_tests
FileTestCase('Test #1', # Test name
'assignment1', # File name
['Palindrome words:kayak', 'Non-palindrome words:hi bonjour'], # Expected output, in a list of strings, each element is a printed line
['kayak hi bonjour'], # Mock input, in a list of strings, each element is a input line
)
FileTestCase('Test #2',
'assignment1',
['Palindrome words:level racecar madam level', 'Non-palindrome words:'],
['level racecar madam level'], # This parameter is optional, if not provided, the test will input nothing
)
FileTestCase('Test #3',
'assignment1',
['Palindrome words:', 'Non-palindrome words:hello world goodbye'],
['hello world goodbye'],
timeout=4, # This parameter is optional, if not provided, the test will timeout after 1 second
)
FileTestCase('Test #4',
'assignment1',
['Palindrome words:KAyak', 'Non-palindrome words:hello world goodbye'],
['hello world goodbye KAyak'],
fail_message='Did you think about case sensitivity?', # This parameter is optional, if not provided, the test will fail with a default message
)
run_tests()
```
This will generate an HTML report that will automatically open in the browser.
![HTML report](https://github.com/school-grader/school-grader/blob/main/assets/html_report1.PNG?raw=true)
If there is an error in the student code, the report will look like this.
![HTML report](https://github.com/school-grader/school-grader/blob/main/assets/html_report2.PNG?raw=true)
## Expected outputs
The expected_output list in FileTestCase can also contains an Equality class object in order to help with string comparison
### Almost equal
- `AlmostEqualString`: This class is used for almost equal string validation:
- `expected`: The expected string value for comparison.
- `max_distance`: The maximum Levenshtein distance allowed between the expected value and the value to test.
- `AlmostEqualNumber`: This class is used for almost equal numerical validation:
- `expected`: The expected string value for comparison.
- `precision`: The number of decimal places to compare for floating-point numbers.
### Equal
- `CaseInsensitiveStringEquality`: This class is used for case-insensitive string equality validation:
- `expected`: The expected string value for comparison.
- `WhiteSpaceInsensitiveEquality`: This class is used for space-insensitive equality validation:
- `expected`: The expected string value for comparison.
- `ContainsEquality`: This class is used for contains equality validation:
- `expected`: The expected string value to check if it is contained in the value to test.
### Combinations of Equal classes
- `CombineEqualities()`: This function combines multiple instances of `Equal` subclasses and returns a new subclass that combines all the provided equalities.
Here is an example using CaseInsentiveStringEquality
```python
from school_grader import FileTestCase, run_tests, CaseInsensitiveStringEquality
FileTestCase('Test #1', # Test name
'assignment1', # File name
[CaseInsensitiveStringEquality('palindrome words:kayak'), CaseInsensitiveStringEquality('non-palindrome words:hi bonjour')], # Expected output
['kayak hi bonjour'], # Mock input, in a list of strings, each element is a input line
)
run_tests() # Run all tests
```
Here is an example combining CaseInsentiveStringEquality and WhiteSpaceInsensitiveEquality
```python
from school_grader import FileTestCase, run_tests, CaseInsensitiveStringEquality, WhiteSpaceInsensitiveEquality, CombineEqualities
Insentive = CombineEqualities(CaseInsensitiveStringEquality, WhiteSpaceInsensitiveEquality)
FileTestCase('Test #1', # Test name
'assignment1', # File name
[Insentive('palindromewords:kayak'), Insentive('non-palindromewords:hibonjour')], # Expected output
['kayak hi bonjour'], # Mock input, in a list of strings, each element is a input line
)
run_tests() # Run all tests
```
## Extension for Visual Studio Code
You can download a Visual Studio Code extension that will provide coloring when running tests.
```python
print('Hi')
```
You can run the tests with these buttons.
![Buttons](https://github.com/school-grader/school-grader/blob/main/assets/extension2.PNG?raw=true)
The result will look like this. When you hover on a test, you will see the Stack trace.
![Result](https://github.com/school-grader/school-grader/blob/main/assets/extension1.PNG?raw=true)
Raw data
{
"_id": null,
"home_page": "",
"name": "school-grader",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "education,framework,python,python3,python3.10,python3.11,python3.7,python3.8,python3.9,school,students,test,testing",
"author": "",
"author_email": "Marc-Olivier Derouin <marcolivier.derouin@poulet-frit.com>",
"download_url": "https://files.pythonhosted.org/packages/7b/a1/ea7b48f76a86ef492edc7febae8488c9527bfe52bce993270df18b57facc/school_grader-4.0.10.tar.gz",
"platform": null,
"description": "# Python Student Testing Framework\n\n## Contents\n\n- [Introduction](#introduction)\n- [Features](#features)\n- [Installation](#installation)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n- [How to use](#how-to-use)\n- [Extension for Visual Studio Code](#extension-for-visual-studio-code)\n\n## Introduction\n\nWelcome to the Python Student Testing Framework! This README provides a brief overview of what the framework is and how to use it. The framework is designed for instructors and TAs to easily test and grade students Python code.\n\n## Features\n\n- Automated testing of students' code against a set of test cases\n- Support for multiple test cases and multiple functions\n- Ability to define custom tests and assertions\n- Clear and detailed feedback for students on test results\n- Display HTML report\n\n## Installation\n\nTo use the Python Student Testing Framework, you will need to have Python installed on your machine. Then, simply clone the repository or install with `pip install school-grader`\n\n\n## Contributing\n\nThe Python Student Testing Framework is an open-source project and contributions are welcome. \n\n## License\n\nThe Python Student Testing Framework is released under the MIT license. See the LICENSE file for more information.\n\n## Contact\n\nIf you have any questions or issues, please create a GitHub issue or reach out to the project maintainers at marcolivier.derouin@poulet-frit.com\n\n\n## How to use\nLet's say you have given an assignment to your students.\n\n### assignment1.py\n```python\nwords = input(\"Please enter a list of words separated by spaces: \").split(\" \")\n\npalindrome_words = []\nnon_palindrome_words = []\n\nfor word in words:\n lowercase_word = word.lower()\n if lowercase_word == lowercase_word[::-1]:\n palindrome_words.append(word)\n else:\n non_palindrome_words.append(word)\n\nprint(\"Palindrome words:\" + \" \".join(palindrome_words))\nprint(\"Non-palindrome words:\" + \" \".join(non_palindrome_words))\n```\nYou can write test case for this assignment using the following code.\n```python\nfrom school_grader import FileTestCase, run_tests\nFileTestCase('Test #1', # Test name\n 'assignment1', # File name\n ['Palindrome words:kayak', 'Non-palindrome words:hi bonjour'], # Expected output, in a list of strings, each element is a printed line\n ['kayak hi bonjour'], # Mock input, in a list of strings, each element is a input line\n )\n\nFileTestCase('Test #2',\n 'assignment1',\n ['Palindrome words:level racecar madam level', 'Non-palindrome words:'],\n ['level racecar madam level'], # This parameter is optional, if not provided, the test will input nothing\n )\n\nFileTestCase('Test #3',\n 'assignment1',\n ['Palindrome words:', 'Non-palindrome words:hello world goodbye'],\n ['hello world goodbye'],\n timeout=4, # This parameter is optional, if not provided, the test will timeout after 1 second\n )\n\nFileTestCase('Test #4',\n 'assignment1',\n ['Palindrome words:KAyak', 'Non-palindrome words:hello world goodbye'],\n ['hello world goodbye KAyak'],\n fail_message='Did you think about case sensitivity?', # This parameter is optional, if not provided, the test will fail with a default message\n )\n\nrun_tests()\n```\n\nThis will generate an HTML report that will automatically open in the browser.\n\n![HTML report](https://github.com/school-grader/school-grader/blob/main/assets/html_report1.PNG?raw=true)\n\nIf there is an error in the student code, the report will look like this.\n\n![HTML report](https://github.com/school-grader/school-grader/blob/main/assets/html_report2.PNG?raw=true)\n\n## Expected outputs\n\nThe expected_output list in FileTestCase can also contains an Equality class object in order to help with string comparison\n\n### Almost equal\n\n- `AlmostEqualString`: This class is used for almost equal string validation:\n - `expected`: The expected string value for comparison.\n - `max_distance`: The maximum Levenshtein distance allowed between the expected value and the value to test.\n\n- `AlmostEqualNumber`: This class is used for almost equal numerical validation:\n - `expected`: The expected string value for comparison.\n - `precision`: The number of decimal places to compare for floating-point numbers.\n\n### Equal\n\n- `CaseInsensitiveStringEquality`: This class is used for case-insensitive string equality validation:\n - `expected`: The expected string value for comparison.\n\n- `WhiteSpaceInsensitiveEquality`: This class is used for space-insensitive equality validation:\n - `expected`: The expected string value for comparison.\n\n- `ContainsEquality`: This class is used for contains equality validation:\n - `expected`: The expected string value to check if it is contained in the value to test.\n\n### Combinations of Equal classes\n\n- `CombineEqualities()`: This function combines multiple instances of `Equal` subclasses and returns a new subclass that combines all the provided equalities.\n\n\nHere is an example using CaseInsentiveStringEquality\n\n```python\nfrom school_grader import FileTestCase, run_tests, CaseInsensitiveStringEquality\nFileTestCase('Test #1', # Test name\n 'assignment1', # File name\n [CaseInsensitiveStringEquality('palindrome words:kayak'), CaseInsensitiveStringEquality('non-palindrome words:hi bonjour')], # Expected output\n ['kayak hi bonjour'], # Mock input, in a list of strings, each element is a input line\n )\n\nrun_tests() # Run all tests\n```\n\nHere is an example combining CaseInsentiveStringEquality and WhiteSpaceInsensitiveEquality\n\n```python\nfrom school_grader import FileTestCase, run_tests, CaseInsensitiveStringEquality, WhiteSpaceInsensitiveEquality, CombineEqualities\n\nInsentive = CombineEqualities(CaseInsensitiveStringEquality, WhiteSpaceInsensitiveEquality)\n\nFileTestCase('Test #1', # Test name\n 'assignment1', # File name\n [Insentive('palindromewords:kayak'), Insentive('non-palindromewords:hibonjour')], # Expected output\n ['kayak hi bonjour'], # Mock input, in a list of strings, each element is a input line\n )\n\nrun_tests() # Run all tests\n```\n## Extension for Visual Studio Code\n\nYou can download a Visual Studio Code extension that will provide coloring when running tests.\n```python\nprint('Hi')\n```\nYou can run the tests with these buttons.\n\n![Buttons](https://github.com/school-grader/school-grader/blob/main/assets/extension2.PNG?raw=true)\n\n\nThe result will look like this. When you hover on a test, you will see the Stack trace.\n\n![Result](https://github.com/school-grader/school-grader/blob/main/assets/extension1.PNG?raw=true)",
"bugtrack_url": null,
"license": "",
"summary": "Testing framework for Python students code.",
"version": "4.0.10",
"project_urls": {
"Bug Tracker": "https://github.com/school-grader/school-grader/issues",
"Homepage": "https://github.com/school-grader/school-grader"
},
"split_keywords": [
"education",
"framework",
"python",
"python3",
"python3.10",
"python3.11",
"python3.7",
"python3.8",
"python3.9",
"school",
"students",
"test",
"testing"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "62ff0afe50795b33e0f3cfb4e023b780ae0c0eafbca885535a7fdeddb022d2ea",
"md5": "88a28c88d455b577450e9b9ef3dfbc30",
"sha256": "fc3ff62ad061c2fcfe9b2b152e876578d0dac81d236206ed147548b82ce3cbdb"
},
"downloads": -1,
"filename": "school_grader-4.0.10-py3-none-any.whl",
"has_sig": false,
"md5_digest": "88a28c88d455b577450e9b9ef3dfbc30",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 11730,
"upload_time": "2023-11-27T15:19:32",
"upload_time_iso_8601": "2023-11-27T15:19:32.658412Z",
"url": "https://files.pythonhosted.org/packages/62/ff/0afe50795b33e0f3cfb4e023b780ae0c0eafbca885535a7fdeddb022d2ea/school_grader-4.0.10-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "7ba1ea7b48f76a86ef492edc7febae8488c9527bfe52bce993270df18b57facc",
"md5": "0d1fe93a762c05c7c9f24ebc4c94cc57",
"sha256": "c98ec6afab028d397b2ffd324e32f4081b9c49e03e2a5a19461a778ca8008a97"
},
"downloads": -1,
"filename": "school_grader-4.0.10.tar.gz",
"has_sig": false,
"md5_digest": "0d1fe93a762c05c7c9f24ebc4c94cc57",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 55618,
"upload_time": "2023-11-27T15:19:34",
"upload_time_iso_8601": "2023-11-27T15:19:34.319779Z",
"url": "https://files.pythonhosted.org/packages/7b/a1/ea7b48f76a86ef492edc7febae8488c9527bfe52bce993270df18b57facc/school_grader-4.0.10.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-11-27 15:19:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "school-grader",
"github_project": "school-grader",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "school-grader"
}