Home > Mobile >  How to test the print to console of a python class?
How to test the print to console of a python class?

Time:08-02

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.

  • Related