I want to test what the print output of a class I am making is. I have tried several approaches based on answers on stackoverflow, but some of the answers are python 2.7 specific, and I couldn't translate them. This is my class:
class trool:
def __init__(self, num : int):
"""
Ternary datatype
"""
if num:
num = 1
if num == 0:
num = -1
if num is None:
num = 0
self._num = num
def __str__(self) -> str:
if self._num == 1:
return 'True'
elif self._num == -1:
return 'False'
else:
return 'Unknown'
def __repr__(self):
return self.__str__()
I have tried some different ways, but they all give me something weird
class TestFunctions(unittest.TestCase):
def setUp(self) -> None:
self.true = trool(True)
self.unknown = trool(None)
self.false = trool(False)
@patch('builtins.print')
def test_print1(self, mock_print):
# The actual test
print(self.true)
mock_print.assert_called_with(True)
print(self.false)
mock_print.assert_called_with(False)
# Showing what is in mock
sys.stdout.write(str( mock_print.call_args ) '\n')
sys.stdout.write(str( mock_print.call_args_list ) '\n')
gives the error
Expected: print(True)
Actual: print(True)
which suggests to me that one of the prints prints the boolean and the other prints the string, but I'm not sure. Another test I tried:
def test_print2(self):
capturedOutput = StringIO()
sys.stdout = capturedOutput
print(trool(True))
sys.stdout = sys.__stdout__
print('Captured', capturedOutput.getvalue())
self.assertEqual('True', capturedOutput.getvalue())
gave me this
AssertionError: 'True' != 'True\n'
but I don't know why I get the '\n' in there. Any feedback is welcome.
CodePudding user response:
In your first test, it's unclear why you would expect it to pass, because you haven't mentioned what your goal for this class is. You created an object that prints out as 'True'
, but is not equal to True
. (In fact, no two trool
objects are ever equal to each other, either.) The results of that test line up perfectly with that. So either you want a different class, or a different test. Is there any chance you wanted to test the output of str()
instead of the input to print()
? That would be a simpler test, and since print()
calls str()
, it's unclear to me why you would need to test print
at all.
For your second test, print()
adds a newline (\n
) to the end of its arguments by default. You can see this by printing to the console: subsequent text will be printed to the following line, not the same line.
If you don't want to print the newline, you can change the end
keyword argument from its default '\n'
to ''
. You might also want to force it to flush, as output is often line-buffered:
print(trool(True), end='', flush=True)
Whenever you change a value, run code that might fail, then change it back, you should use try
/finally
or a context manager to ensure you really do change it back.
If you're calling print
yourself in your test, there's an easier and safer way to test the output of print
than messing around with stdout
. The file
keyword argument lets you send its output straight to your StringIO object.
Of course, like with your first test, there's no clear need to test print
here, when you could be testing str
.
See also the print()
documentation.