How do I write multiple test cases for a single function. I want the functions to essentially iterate through a bunch of tests and then return a boolean or answer saying that the function has passed these tests.
def test_valid01():
name = 'jack'
expected = True
assert is_valid_name(name) == expected, "is_valid_name has failed."
test1 = True
this is an example of one of my functions testing another function.
A way that you could test various tests for the is_valid_name() function:
def assert_test_valid(name, expected_value):
assert is_valid_name(name) == expected_value, f"is_valid_name has failed for {name}" # allows identification of which test failed
def test_valid_all():
test_responses = { # the input and the expected response
'jack': True,
}
for key, value in test_responses.items(): # to go through all of the responses that you would like to test
assert_test_valid(key, value)
Related
I have a parameterized test that receives a long string as an argument, and the problem is that when executing pytest it prints the entire string
#pytest.mark.parametrize(
"long_string_p1, long_string_p2",
[
(a,b) for a,b in zip(list_str_1, list_str_2)
]
)
def test_with_long_strings(long_string_p1, long_string_p2):
# Logic
assert long_string_p1 != long_string_p2
pytest
test_example.py::test_with_long_strings[looooooooong string1-loooooooooong string2] PASSED
I would like it to only show the last part of the string, somehow change the logic so that it doesn't show the whole string but only a part
You should be able to use pytest.param to enhance the id values used. Could make a helper to determine the name based on your custom logic.
Here's an example where it strips off the last value in the string and joins them with a dash:
import pytest
list_str_1 = ["looooooooong string1"]
list_str_2 = ["loooooooooong string2"]
def make_param(args):
return pytest.param(*args, id='-'.join([s.split(" ")[-1] for s in args]))
#pytest.mark.parametrize(
"long_string_p1, long_string_p2",
list(map(make_param, zip(list_str_1, list_str_2)))
)
def test_with_long_strings(long_string_p1, long_string_p2):
assert long_string_p1 != long_string_p2
You can also supply a function as the ids argument to format each entry individually:
import pytest
list_str_1 = ["looooooooong string1"]
list_str_2 = ["loooooooooong string2"]
def id_function(val):
return val.split(" ")[-1]
#pytest.mark.parametrize(
"long_string_p1, long_string_p2",
[*zip(list_str_1, list_str_2)],
ids=id_function
)
def test_with_long_strings(long_string_p1, long_string_p2):
assert long_string_p1 != long_string_p2
Let's say I have a Python method:
def good_method(self) -> None:
txt = "Some text"
response = self.bad_method(txt)
resources = response["resources"]
print (resources)
while resources:
response = self.bad_method(txt)
resources = response["resources"]
print (resources)
Now let's say I want to write a unit test for it. The bad_method() returns a dictionary and it could get called over and over in the while loop. I have been trying to Mock the bad_method() so it returns a nested dictionary, so the while loop runs once. This is the code:
from unittest.mock import MagicMock
def test_good_method():
dic = {"resources": {"resources": "values"}}
def side_effect():
return dic
self.bad_method() = MagicMock(side_effect=side_effect())
self.good_method()
I expected to first get a {"resources": "values"} printed out, and then a values. But the only thing I get is a resources. What am I doing wrong? How can I achieve what I expect?
def test_good_method():
thing = MyClassContainingGoodAndBadMethod()
thing.bad_method = MagicMock(return_value={"a": "b"})
thing.good_method()
assert thing.bad_method.call_count == 10 # or however many times it is supposed to be called
Everyone
I have a function which is the handler for aws lambdafunction.
def data_list(event, data_subject):
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("TestTable")
print("DATA_LIST")
def get_col_name(data_subject):
if data_subject == "X":
return 'something'
elif data_subject == "y":
return 'some other things'
elif data_subject == "c":
return 'really'
def another_function(var):
pass
I have multiple function under data_list function how can we write unittest cases for each individual function which is under data_list function
Don't.
Instead move them out from the lambda handler function so that you can test them entirely separately.
Then make the lambda handler function it's self so small and simple that you barely need to test it, and can handle testing it with system tests.
I have a utility function that takes the argument case and return the value accordingly
helper.py
def get_sport_associated_value(dictionary, category, case):
if case == 'type':
return "soccer"
else:
return 1 #if case = 'id'
I have a main function that use the above function
crud_operations.py
def get_data(category):
dictionary ={.....}
id = get_sport_associated_value(dictionary, category, 'id')
.....
.....
type = get_sport_associated_value(dictionary, category, 'type')
....
return "successful"
Now I am unittesting the get_data() module using the unittest.Mock. I am having trouble passing the values to id and type.
#mock.patch('helper.get_sport_associated_value')
def test_get_data(self, mock_sport):
with app.app_context():
mock_sport.side_effect = self.side_effect
mock_sport.get_sport_associated_value("id")
mock_sport.get_sport_associated_value("type")
result = get_queries("Soccer")
asserEquals(result, "successful")
def side_effect(*args, **kwargs):
if args[0] == "type":
print("Soccer")
return "Soccer"
elif args[0] == "id":
print("1")
return 1
I tried this using side_effect function and facing problem to mock the get_sport_associated_value() according to the different values of input argument.
Question 2 : Which is the best method to use mock or mock.magicmock in this scenario?
Any help is appreciated with unit testing
Thanks
You're incorrectly testing args[0] as a case. The arguments of the side_effect callback function should be the same as the function you want to mock:
def side_effect(dictionary, category, case):
if case == "type":
return "Soccer"
elif case == "id":
return 1
I have a class:
class AccountBusiness:
def save(self, account) -> Account:
if not account.account_number_is_valid():
return False
return True
and a test as:
#mock.patch.object(AccountBusiness, 'save')
def test_can_save_valid_account(self, mock_save):
mock_account = mock.create_autospec(Account)
mock_account.account_number_is_valid.return_value = False
account_business = AccountBusiness()
result = account_business.save(mock_account)
self.assertEqual(result.return_value, True)
but it shows an exception like:
AssertionError: <MagicMock name='save()()' id='48830448'> != True
I want to set the return value of account.account_number_is_valid() to False and run the test.
You are using a patch object on the instance method you are looking to test. However, you are looking to test the logic inside the save method. So mocking that out will not test any of the logic inside that method. So, the output you are actually getting here:
AssertionError: <MagicMock name='save()()' id='48830448'> != True
Should be the first hint that something is not right. Your save method is coming back as a MagicMock. You don't want this. What you actually want to do is only mock the Account class, and go accordingly from there. So, your patching here:
#mock.patch.object(AccountBusiness, 'save')
should actually only be:
#mock.patch('path.to.AccountBusiness.Account', return_value=Mock(), autospec=True)
The path.to.AccountBusiness.Account is the location of the Account class with respect to the AccountBusiness class.
So, with that patching, then the return_value of calling Account will now be your mock object that you can use for your account_number_is_valid. So, the code will actually look like this:
class MyTest(unittest.TestCase):
def setUp(self):
self.account_business = AccountBusiness()
#mock.patch('path.to.AccountBusiness.Account', return_value=Mock(), autospec=True)
def test_can_save_valid_account(self, mock_account):
mock_account_obj = mock_account.return_value
mock_account_obj.account_number_is_valid.return_value = False
self.assertFalse(self.account_business.save(mock_account_obj))
Also, pay close attention to the assertion at the end. It was changed to make use of the available assertFalse. Also, look over your own logic, as returning False for account_number_is_valid will actually return False in your save method.