Package to add a data_provider decorator to a unit test function,
Project description
Python Unittest dataprovider
Description
Python package to add a data_provider
decorator to a unit test function,
to execute the test with different test values / cases.
The test function will be executed for each record, which is defined at the data_provider
.
@data_provider([ # The DataSet as a List
(value1, value2, value3), # Record 1
(value1, value2, value3) # Record 2
(value1, value2, value3) # Record 3
])
The data_provider accepts the following Types as argument
- Function
- Dict
- List
- Tuple
This package is a Python version of the PHP UnitTest dataprovider.
https://phpunit.de/manual/3.7/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers
Installation
pip install sat_unittest_dataprovider
or
python -m pip install sat_unittest_dataprovider
Usage
The test method will be called with the values of the record as arguments
Therefor you need to make sure, to define the same amount of arguments at the test function,
as you defined values at the record.@data_provider([ (arg1, arg2, arg3, arg4) ]) def test_multiply(arg1, arg2, arg3, arg4): ... do something with the arguments ...
Without the unittest data provider you would probably create a test like this:
class Test(TestCase): def test_without_dataprovider(self): test_data = [ (1, 1, '1 * 1 is 1'), (2, 4, '2 * 2 is 4') ] for row in test_data: given_value, expected_result, msg = row # We unpack the tuple here calculated_result = given_value * given_value # Calculation self.assertEqual(expected_result, calculated_result, msg) # The Test
The same test with the data_provider decorator would look like this:
class Test(TestCase): @data_provider([ (1, 1, '1 * 1 is 1'), (2, 4, '2 * 2 is 4') ]) def test_with_dataprovider(self, given_value, expected_result, msg): # We get all values as function arguments calculated_result = given_value * given_value # Calculation self.assertEqual(expected_result, calculated_result, msg) # The TestThis makes the test more readable to others.
Simple example:
@data_provider([
(1, 2, 3, '1 + 2 = 3')
])
def test_simple_example(self, value, value2, expected, msg):
self.assertEqual(expected, value + value2, msg)
At the example above, we define 4 values at the record, we want to test a simple number addition.
The first argumentvalue
will be added to the second argumentvalue2
and we expect,
that the calculated result is the same as defined inexpected
.
The last argumentmsg
is used as a message which will be shown, when the test fails.
Example 1:
DataSet is a List of Tupels
from unittest import TestCase
from sat_unittest_dataprovider import data_provider
class Test(TestCase):
@data_provider([
(1, 1, '1 * 1 is 1'),
(2, 4, '2 * 2 is 4'),
(3, 9, '3 * 3 is 9')
])
def test_multiply(self, given, expected, message):
calculated_result = given * given
self.assertEqual(expected, calculated_result, message)
Example 2:
DataSet is a List with List items
from unittest import TestCase
from sat_unittest_dataprovider import data_provider
class Test(TestCase):
@data_provider([
[1, 1, '1 * 1 is 1'],
[2, 4, '2 * 2 is 4'],
[3, 9, '3 * 3 is 9']
])
def test_multiply(self, given, expected, message):
calculated_result = given * given
self.assertEqual(expected, calculated_result, message)
Example 3:
DataSet is a Function, which should return the test records either as List, Dict or Tuple
from unittest import TestCase
from sat_unittest_dataprovider import data_provider
def my_data_set():
return [
[1, 1, '1 * 1 is 1'],
[2, 4, '2 * 2 is 4'],
[3, 9, '3 * 3 is 9']
]
class Test(TestCase):
@data_provider(my_data_set)
def test_multiply(self, given, expected, message):
calculated_result = given * given
self.assertEqual(expected, calculated_result, message)
@data_provider(my_data_set)
def test_divider(self, divider, given, message):
expected_result = divider # the expected result is the same as the divider
calculated_result = given / divider
self.assertEqual(expected_result, calculated_result) # We don't use the message here, because for this test it doesn't make sense ;-)
In the example above, you can use the data_set function for multiple test cases
to reduce code duplication
Example 4:
DataSet is a seperate file
For bigger tests you can place the provider functions or values in a separate file
test/data_providers.py
def tuples_in_list() -> list[tuple[int, int, int, str]]:
return [
(1, 2, 3, '1 + 2 is 3'),
(2, 2, 4, '2 + 2 is 3')
]
def tuples_in_tuple() -> tuple[tuple[int, int, int, str], ...]:
return (
(1, 2, 3, '1 + 2 is 3'),
(2, 2, 4, '2 + 2 is 3'),
)
def dict_with_tuples() -> dict[str, tuple[int, int, int, str]]:
return {
"record_1": (1, 2, 3, '1 + 2 is 3'),
"record_2": (2, 2, 4, '2 + 2 is 3'),
}
a_dict: dict[str, tuple[int, int, int, str]] = {
"record_1": (1, 2, 3, '1 + 2 is 3'),
"record_2": (2, 2, 4, '2 + 2 is 3'),
}
test/test_readme_examples.py
from unittest import TestCase
from sat_unittest_dataprovider import data_provider
from .data_providers import (
tuples_in_list,
tuples_in_tuple,
dict_with_tuples,
a_dict
)
class Test(TestCase):
@data_provider(tuples_in_list)
def test_addition_with_tuples_in_list(self, value1, value2, expected, msg):
self.assertEqual(expected, value1 + value2, msg)
@data_provider(tuples_in_tuple)
def test_addition_with_tuples_in_tuple(self, value1, value2, expected, msg):
self.assertEqual(expected, value1 + value2, msg)
@data_provider(dict_with_tuples)
def test_addition_with_dict_with_tuples(self, value1, value2, expected, msg):
self.assertEqual(expected, value1 + value2, msg)
@data_provider(a_dict)
def test_addition_with_a_dict(self, value1, value2, expected, msg):
self.assertEqual(expected, value1 + value2, msg)
A real world Example
We have a function, which will convert a snake_case
value to an camelCase
value.
The function looks like this
'tests/real_world_example.py'
def snake_case_to_camel_case(snake_case_value: str, first_to_upper: bool = False) -> str:
"""
This function converts a given snake_case value to an camelCase,
optionally you could set first_to_upper = True to return a string where the first
letter is upper case as well ( camel_case => CamelCase )
:param snake_case_value: The snake case value
:param first_to_upper: If True, the first letter of the first item will be uppercase as well
:return: The camelCase string
"""
snake_case_items = snake_case_value.split("_") # we split the value at each `_` underscore
camel_case_items: list = list() # a list to store the converted items
for index, item in enumerate(snake_case_items):
first_letter = item[:1] # we get the first letter of the item
the_rest = item[1:] # we get the rest of the string, excluding the first letter
# make sure the first item is lower case
if first_to_upper is False and index == 0:
camel_case_items.append(first_letter.lower() + the_rest)
else:
camel_case_items.append(first_letter.upper() + the_rest)
return "".join(camel_case_items)
The unit test would look like this.
We define 14 Test cases, within the data_provider decorator
@data_provider([
# The snake case value | First item upper | The Expected Result | The failure message
("some_camel_case_string", True, "SomeCamelCaseString", "Test Case 1, first item upper"),
("this_is_Another_string", True, "ThisIsAnotherString", "Test Case 2, first item upper"),
("ThisIsAlreadyCamelCase", True, "ThisIsAlreadyCamelCase", "Test Case 3, first item upper"),
("This_is_an_other_Test", True, "ThisIsAnOtherTest", "Test Case 4, first item upper"),
("This_is_an_OtHer_Test", True, "ThisIsAnOtHerTest", "Test Case 5, first item upper"),
("a_b_c_d_e_f_g_h_i_j_k", True, "ABCDEFGHIJK", "Test Case 6, first item upper"),
("test_with_2_numbers_1_and_2", True, "TestWith2Numbers1And2", "Test Case 7, first item upper"),
# No we run the same test, but this time, the first item should be lower case
("some_camel_case_string", False, "someCamelCaseString", "Test Case 8, first item lower"),
("this_is_Another_string", False, "thisIsAnotherString", "Test Case 9, first item lower"),
("ThisIsAlreadyCamelCase", False, "thisIsAlreadyCamelCase", "Test Case 10, first item lower"),
("This_is_an_other_Test", False, "thisIsAnOtherTest", "Test Case 11, first item lower"),
("This_is_an_OtHer_Test", False, "thisIsAnOtHerTest", "Test Case 12, first item lower"),
("a_b_c_d_e_f_g_h_i_j_k", False, "aBCDEFGHIJK", "Test Case 13, first item lower"),
("test_with_2_numbers_1_and_2", False, "testWith2Numbers1And2", "Test Case 14, first item lower")
])
The first half of the test cases are designed to test that the result should return a converted value,
where the first letter is upper case as well.
(
"some_camel_case_string", # The snake case value
True, # First letter should be upper case as well
"SomeCamelCaseString", # The Expected Result
"Test Case 1, first item upper" # The failure message
),
...
The second half will test, that the result should return a converted value, where the first letter is lower case.
(
"some_camel_case_string", # The snake case value
False, # First letter should not be upper case
"someCamelCaseString", # The Expected Result
"Test Case8, first item lower" # The failure message
),
'tests/test_readme_examples.py'
from unittest import TestCase
from sat_unittest_dataprovider import data_provider
from .real_world_example import snake_case_to_camel_case
class Test(TestCase):
@data_provider([
# The snake case value | First item upper | The Expected Result | The failure message
("some_camel_case_string", True, "SomeCamelCaseString", "Test Case 1, first item upper"),
("this_is_Another_string", True, "ThisIsAnotherString", "Test Case 2, first item upper"),
("ThisIsAlreadyCamelCase", True, "ThisIsAlreadyCamelCase", "Test Case 3, first item upper"),
("This_is_an_other_Test", True, "ThisIsAnOtherTest", "Test Case 4, first item upper"),
("This_is_an_OtHer_Test", True, "ThisIsAnOtHerTest", "Test Case 5, first item upper"),
("a_b_c_d_e_f_g_h_i_j_k", True, "ABCDEFGHIJK", "Test Case 6, first item upper"),
("test_with_2_numbers_1_and_2", True, "TestWith2Numbers1And2", "Test Case 7, first item upper"),
# No we run the same test, but this time, the first item should be lower case
("some_camel_case_string", False, "someCamelCaseString", "Test Case 8, first item lower"),
("this_is_Another_string", False, "thisIsAnotherString", "Test Case 9, first item lower"),
("ThisIsAlreadyCamelCase", False, "thisIsAlreadyCamelCase", "Test Case 10, first item lower"),
("This_is_an_other_Test", False, "thisIsAnOtherTest", "Test Case 11, first item lower"),
("This_is_an_OtHer_Test", False, "thisIsAnOtHerTest", "Test Case 12, first item lower"),
("a_b_c_d_e_f_g_h_i_j_k", False, "aBCDEFGHIJK", "Test Case 13, first item lower"),
("test_with_2_numbers_1_and_2", False, "testWith2Numbers1And2", "Test Case 14, first item lower")
])
def test_snake_case_to_camel_case(self, given_value, first_item_upper, expected_value, msg):
camel_case: str = snake_case_to_camel_case(given_value, first_item_upper)
self.assertEqual(expected_value, camel_case, msg)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file sat_unittest_dataprovider-1.0.1.tar.gz
.
File metadata
- Download URL: sat_unittest_dataprovider-1.0.1.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e9446cdcbb0f5cb13d1e18cd437c8de578653b091247a436f8feb556de4cea8b |
|
MD5 | a994c13a51fe4829d8b8e1cc2b11841c |
|
BLAKE2b-256 | 0d58d1caa4c85782993331235fb1ce6df429b4bc18a9c1f78d9831dfaa70931b |
File details
Details for the file sat_unittest_dataprovider-1.0.1-py3-none-any.whl
.
File metadata
- Download URL: sat_unittest_dataprovider-1.0.1-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0720c66ab6d9076eaf396c490834c723feefd508c7d206cf43b45293162db43e |
|
MD5 | 229c483e62320061a14fd2f01ec32b95 |
|
BLAKE2b-256 | 968271a4b4410932929a7fbbfeb2654fde2a3d294177e3765c7f7f27d42fee0a |