I am trying to become a responsible programmer and test my code. I came up with the following hypotheticals and I am unable to find a way to run all tests using python's built in mock library. I have been unable to get any of the tests to complete properly.....
I am using python 3.6.4
protos.py
#import asyncio #not really necessary here for the example
class resultObject:
def __init__(self, result, error):
self.result = result
self.error = error
self.ran = 1
async def get_results(self):
#await asyncio.sleep(0.1) #not really necessary for the example
return self.result, self.error
async def function_to_mock(instruction):
if not isinstance(instruction, str):
raise RuntimeError("Instruction is not a string") #inner error
if " " in instruction:
error = "Instruction contains a space"
else:
error = None
result = f"Instruction: {instruction} was run"
#await asyncio.sleep(0.1) #not really necessary for the example
return resultObject(result, error)
async def function_to_test(instruction):
output = await function_to_mock(instruction)
result, error = await output.get_results()
print(output.ran)
if error: #outer error
raise RuntimeError("No Spaces Allowed")
return result
mytest.py
import unittest
from unittest.mock import patch
from unittest.mock import MagicMock
from protos import function_to_test
class tester(unittest.TestCase):
def setUp(self):
import asyncio
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(None)
def tearDown(self):
self.loop.close()
def test_valid_instruction(self, instruction = "valid_instruction"):
with patch("protos.function_to_mock", autospec=True, return_value=MagicMock(result="Instruction: valid_instruction was run", error=None)) as MockFunc:
result = self.loop.run_until_complete(function_to_test(instruction))
MockFunc.assert_called_once_with(instruction)
self.assertEqual(result, "Instruction: valid_instruction was run" )
def test_invalid_instruction(self, instruction=["invalid_instruction"]):
with patch("protos.function_to_mock", autospec=True, sideffect=RuntimeError("Instruction is not a string")) as MockFunc:
with self.assertRaises(RuntimeError) as cm:
self.loop.run_until_complete(function_to_test(instruction))
e = cm.exception
self.assertEqual(e.args[0], "Instruction is not a string")
MockFunc.assert_called_once_with(instruction)
def test_spacein_instruction(self, instruction = "in valid_instruction"):
with patch("protos.function_to_mock", autospec=True, return_value=MagicMock(result="Instruction: in valid_instruction was run", error="Instruction contains a space")) as MockFunc:
with self.assertRaises(RuntimeError) as cm:
result = self.loop.run_until_complete(function_to_test(instruction))
e = cm.exception
self.assertEqual(e.args[0], "No Spaces Allowed")
MockFunc.assert_called_once_with(instruction)
if __name__ == '__main__':
unittest.main()
Output
python3.6 mytests.py
.
.
.
TypeError: object MagicMock can't be used in 'await' expression
Explanation
I have a function that runs an instruction. There are three cases, (i) a valid instruction (i.e. string with no spaces), (ii) an invalid instruction type where the type of the instruction is wrong (i.e. not a string), and (iii) finally an invalid instruction (i.e. an instruction that has a space in it). This is a "simplified" hypothetical approximation. The issue seems to be that it can't await the MagicMock object and I have not found a satisfactory way to work around it.
Aucun commentaire:
Enregistrer un commentaire