3

I would like to test the following statement

with open('test.txt', 'w') as f:
    print(['abc', 20], end='', file=f)

I tried

  from __future__ import print_function                                              
  from mock import patch, mock_open                                                  


  def f():                                                                           
      with open('test.txt', 'w') as f:                                               

          # f.write(str(['abc', 20]))                                                 
          print(['abc', 20], end='', file=f)                                         


  @patch('__builtin__.open', new_callable=mock_open)                                 
  def test(mock_f):                                                                  
      f()                                                                            
      mock_f.assert_called_with('test.txt', 'w')                                     
      handle = mock_f()                                                              
      handle.write.assert_called_once_with(str(['abc', 20])) 

It complains that write is never called, which makes sense. In this case, what is the proper way to check the content for writing?

I also tried to use f.write(str(['abc', 20])) instead of the print statement, which passes the test. Is it just a bad idea to use print?

5
  • You could check that f.tell() is not zero; though it is a bit of a work-around Commented Sep 6, 2017 at 16:50
  • @James Can you give more details? Commented Sep 6, 2017 at 17:02
  • Seems like your mock open would need to emulate a context manager and return an instance of a mock file - then it would be the mock file that has the .write assertion(s). Commented Sep 6, 2017 at 18:49
  • There is an example in tthe docs that looks like what you are trying to do. Commented Sep 6, 2017 at 18:59
  • @wwii, I don't think that the example from docs, is what he wants. He is mocking the open method, and his assert is matching with print function. That is the error. Commented Sep 8, 2017 at 12:37

1 Answer 1

3

Python 3.6:

If you inspect the mock object you can see that the thing you are looking for is there.

from unittest.mock import mock_open, patch

def f():                                                                           
    with open('test.txt', 'w') as f:                                               

        print(['abc', 20], end='', file=f)                                         

@patch('__main__.__builtins__.open', new_callable=mock_open)                                 
def test(mock_f):
    f()
    mock_f.assert_called_with('test.txt', 'w')
    print('calls to open:\n', mock_f.mock_calls, end ='\n\n')
    handle = mock_f()
    print('calls to the file:\n', handle.mock_calls, end ='\n\n')
    print('calls to write:\n', handle.write.mock_calls, end ='\n\n')
    handle.write.assert_called_once_with(str(['abc', 20]))

>>> test()
calls to open:
 [call('test.txt', 'w'),
 call().__enter__(),
 call().write("['abc', 20]"),
 call().write(''),
 call().__exit__(None, None, None)]

calls to the file:
 [call.__enter__(),
 call.write("['abc', 20]"),
 call.write(''),
 call.__exit__(None, None, None)]

calls to write:
 [call("['abc', 20]"), call('')]

Traceback (most recent call last):
  File "<pyshell#98>", line 1, in <module>
    test()
  File "C:\Python36\lib\unittest\mock.py", line 1179, in patched
    return func(*args, **keywargs)
  File "C:/pyProjects33/test_tmp.py", line 30, in test
    handle.write.assert_called_once_with(str(['abc', 20]))
  File "C:\Python36\lib\unittest\mock.py", line 824, in assert_called_once_with
    raise AssertionError(msg)
AssertionError: Expected 'write' to be called once. Called 2 times.
>>> 

.write() is being called a second time with '' because of the end argument you passed - you can verify this by playing around with that parameter.

How to test? You could use assert_any_call() :

    handle.write.assert_any_call(str(['abc', 20]))

or, if you want to validate the end argument, assert_has_calls():

from unittest.mock import call

....
        calls = [call(str(['abc', 20])), call('')]
        handle.write.assert_has_calls(calls)

You asked Is it just a bad idea to use print? | Maybe someone else can chime in but in my limited experience I have never consider using print() to write to a file.

Sign up to request clarification or add additional context in comments.

1 Comment

Dammit! I was writing the answer, but took a break to lunch! It was pretty much similar to your answer. Good job!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.