Python 3 Context Manager Mock Unit Test










1















I have the following bit of code.



import yaml

def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)

return data


Is there a way to mock the open part so that f becomes '"hello":"world"' and thus I can assert that data is properly returned.



I tried to mock open with mock_open.return_value.__enter__.return_value = '"hello":"world"' and couldn't get it to work properly.



I'm using pytest and mocker.










share|improve this question






















  • Nothing to do with your question, but are you sure you need yaml.load() and that yaml.safe_load() wouldn't do the job? Even if you need to load specific objects from the standard Python library, it is better to register those explicitly for safe_loading, than to use the potentially unsafe load()

    – Anthon
    Nov 24 '18 at 20:06











  • Anthon - Very very good point, thank you for pointing that out!

    – ClickThisNick
    Nov 26 '18 at 14:40















1















I have the following bit of code.



import yaml

def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)

return data


Is there a way to mock the open part so that f becomes '"hello":"world"' and thus I can assert that data is properly returned.



I tried to mock open with mock_open.return_value.__enter__.return_value = '"hello":"world"' and couldn't get it to work properly.



I'm using pytest and mocker.










share|improve this question






















  • Nothing to do with your question, but are you sure you need yaml.load() and that yaml.safe_load() wouldn't do the job? Even if you need to load specific objects from the standard Python library, it is better to register those explicitly for safe_loading, than to use the potentially unsafe load()

    – Anthon
    Nov 24 '18 at 20:06











  • Anthon - Very very good point, thank you for pointing that out!

    – ClickThisNick
    Nov 26 '18 at 14:40













1












1








1








I have the following bit of code.



import yaml

def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)

return data


Is there a way to mock the open part so that f becomes '"hello":"world"' and thus I can assert that data is properly returned.



I tried to mock open with mock_open.return_value.__enter__.return_value = '"hello":"world"' and couldn't get it to work properly.



I'm using pytest and mocker.










share|improve this question














I have the following bit of code.



import yaml

def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)

return data


Is there a way to mock the open part so that f becomes '"hello":"world"' and thus I can assert that data is properly returned.



I tried to mock open with mock_open.return_value.__enter__.return_value = '"hello":"world"' and couldn't get it to work properly.



I'm using pytest and mocker.







python-3.x unit-testing mocking pytest






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 14:06









ClickThisNickClickThisNick

2,02182448




2,02182448












  • Nothing to do with your question, but are you sure you need yaml.load() and that yaml.safe_load() wouldn't do the job? Even if you need to load specific objects from the standard Python library, it is better to register those explicitly for safe_loading, than to use the potentially unsafe load()

    – Anthon
    Nov 24 '18 at 20:06











  • Anthon - Very very good point, thank you for pointing that out!

    – ClickThisNick
    Nov 26 '18 at 14:40

















  • Nothing to do with your question, but are you sure you need yaml.load() and that yaml.safe_load() wouldn't do the job? Even if you need to load specific objects from the standard Python library, it is better to register those explicitly for safe_loading, than to use the potentially unsafe load()

    – Anthon
    Nov 24 '18 at 20:06











  • Anthon - Very very good point, thank you for pointing that out!

    – ClickThisNick
    Nov 26 '18 at 14:40
















Nothing to do with your question, but are you sure you need yaml.load() and that yaml.safe_load() wouldn't do the job? Even if you need to load specific objects from the standard Python library, it is better to register those explicitly for safe_loading, than to use the potentially unsafe load()

– Anthon
Nov 24 '18 at 20:06





Nothing to do with your question, but are you sure you need yaml.load() and that yaml.safe_load() wouldn't do the job? Even if you need to load specific objects from the standard Python library, it is better to register those explicitly for safe_loading, than to use the potentially unsafe load()

– Anthon
Nov 24 '18 at 20:06













Anthon - Very very good point, thank you for pointing that out!

– ClickThisNick
Nov 26 '18 at 14:40





Anthon - Very very good point, thank you for pointing that out!

– ClickThisNick
Nov 26 '18 at 14:40












2 Answers
2






active

oldest

votes


















1





+50









DISCLAIMERS



  • This solution does not use Mocker, but can be used with pytest.

  • This solution works for Python >= 3.6

As you said you are using Mocker, I will assume that you are working on a very old codebase (<= 2.6). I highly recommend you port you code to any version >= 3.6



Since Python 3.3 mock is integrated to standard lib in unittest.mock and is a pretty much clone from old mock package



The mock lib has a feature called mock_open that does exactly what you need and has an example with exactly what you want.



with patch('__main__.open', mock_open(read_data='bibble')) as m:
with open('foo') as h:
result = h.read()

m.assert_called_once_with('foo')
assert result == 'bibble'


Adapting the solution to your need you can use this example



import yaml
from unittest.mock import patch, mock_open

def load_yaml_file(filename):
with open(filename, 'rt') as f:
data = yaml.load(f)

return data

with patch('__main__.open', mock_open(read_data='"hello":"world"')) as m:
res = load_yaml_file('foo')

assert res == "hello":"world"





share|improve this answer






























    1














    You don't need to set __enter__ at all. Just pass in the data you want read as the read_data argument to mock_open():



    mocked_open = mock.mock_open(read_data='"hello":"world"')
    with mock.patch("yourmodule.open", mocked_open):
    result = load_yaml_file("foobar.yaml")


    Demonstration:



    >>> import yaml
    >>> def load_yaml_file(filename):
    ... with open(filename, 'rt') as f:
    ... data = yaml.load(f)
    ... return data
    ...
    >>> from unittest import mock
    >>> mocked_open = mock.mock_open(read_data='"hello":"world"')
    >>> with mock.patch("__main__.open", mocked_open):
    ... result = load_yaml_file("foobar.yaml")
    ...
    >>> print(result)
    'hello': 'world'
    >>> mocked_open.mock_calls
    [call('foobar.yaml', 'rt'),
    call().__enter__(),
    call().read(4096),
    call().read(4096),
    call().__exit__(None, None, None)]





    share|improve this answer






















      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53282809%2fpython-3-context-manager-mock-unit-test%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1





      +50









      DISCLAIMERS



      • This solution does not use Mocker, but can be used with pytest.

      • This solution works for Python >= 3.6

      As you said you are using Mocker, I will assume that you are working on a very old codebase (<= 2.6). I highly recommend you port you code to any version >= 3.6



      Since Python 3.3 mock is integrated to standard lib in unittest.mock and is a pretty much clone from old mock package



      The mock lib has a feature called mock_open that does exactly what you need and has an example with exactly what you want.



      with patch('__main__.open', mock_open(read_data='bibble')) as m:
      with open('foo') as h:
      result = h.read()

      m.assert_called_once_with('foo')
      assert result == 'bibble'


      Adapting the solution to your need you can use this example



      import yaml
      from unittest.mock import patch, mock_open

      def load_yaml_file(filename):
      with open(filename, 'rt') as f:
      data = yaml.load(f)

      return data

      with patch('__main__.open', mock_open(read_data='"hello":"world"')) as m:
      res = load_yaml_file('foo')

      assert res == "hello":"world"





      share|improve this answer



























        1





        +50









        DISCLAIMERS



        • This solution does not use Mocker, but can be used with pytest.

        • This solution works for Python >= 3.6

        As you said you are using Mocker, I will assume that you are working on a very old codebase (<= 2.6). I highly recommend you port you code to any version >= 3.6



        Since Python 3.3 mock is integrated to standard lib in unittest.mock and is a pretty much clone from old mock package



        The mock lib has a feature called mock_open that does exactly what you need and has an example with exactly what you want.



        with patch('__main__.open', mock_open(read_data='bibble')) as m:
        with open('foo') as h:
        result = h.read()

        m.assert_called_once_with('foo')
        assert result == 'bibble'


        Adapting the solution to your need you can use this example



        import yaml
        from unittest.mock import patch, mock_open

        def load_yaml_file(filename):
        with open(filename, 'rt') as f:
        data = yaml.load(f)

        return data

        with patch('__main__.open', mock_open(read_data='"hello":"world"')) as m:
        res = load_yaml_file('foo')

        assert res == "hello":"world"





        share|improve this answer

























          1





          +50







          1





          +50



          1




          +50





          DISCLAIMERS



          • This solution does not use Mocker, but can be used with pytest.

          • This solution works for Python >= 3.6

          As you said you are using Mocker, I will assume that you are working on a very old codebase (<= 2.6). I highly recommend you port you code to any version >= 3.6



          Since Python 3.3 mock is integrated to standard lib in unittest.mock and is a pretty much clone from old mock package



          The mock lib has a feature called mock_open that does exactly what you need and has an example with exactly what you want.



          with patch('__main__.open', mock_open(read_data='bibble')) as m:
          with open('foo') as h:
          result = h.read()

          m.assert_called_once_with('foo')
          assert result == 'bibble'


          Adapting the solution to your need you can use this example



          import yaml
          from unittest.mock import patch, mock_open

          def load_yaml_file(filename):
          with open(filename, 'rt') as f:
          data = yaml.load(f)

          return data

          with patch('__main__.open', mock_open(read_data='"hello":"world"')) as m:
          res = load_yaml_file('foo')

          assert res == "hello":"world"





          share|improve this answer













          DISCLAIMERS



          • This solution does not use Mocker, but can be used with pytest.

          • This solution works for Python >= 3.6

          As you said you are using Mocker, I will assume that you are working on a very old codebase (<= 2.6). I highly recommend you port you code to any version >= 3.6



          Since Python 3.3 mock is integrated to standard lib in unittest.mock and is a pretty much clone from old mock package



          The mock lib has a feature called mock_open that does exactly what you need and has an example with exactly what you want.



          with patch('__main__.open', mock_open(read_data='bibble')) as m:
          with open('foo') as h:
          result = h.read()

          m.assert_called_once_with('foo')
          assert result == 'bibble'


          Adapting the solution to your need you can use this example



          import yaml
          from unittest.mock import patch, mock_open

          def load_yaml_file(filename):
          with open(filename, 'rt') as f:
          data = yaml.load(f)

          return data

          with patch('__main__.open', mock_open(read_data='"hello":"world"')) as m:
          res = load_yaml_file('foo')

          assert res == "hello":"world"






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 24 '18 at 4:42









          Mauro BaraldiMauro Baraldi

          3,92112031




          3,92112031























              1














              You don't need to set __enter__ at all. Just pass in the data you want read as the read_data argument to mock_open():



              mocked_open = mock.mock_open(read_data='"hello":"world"')
              with mock.patch("yourmodule.open", mocked_open):
              result = load_yaml_file("foobar.yaml")


              Demonstration:



              >>> import yaml
              >>> def load_yaml_file(filename):
              ... with open(filename, 'rt') as f:
              ... data = yaml.load(f)
              ... return data
              ...
              >>> from unittest import mock
              >>> mocked_open = mock.mock_open(read_data='"hello":"world"')
              >>> with mock.patch("__main__.open", mocked_open):
              ... result = load_yaml_file("foobar.yaml")
              ...
              >>> print(result)
              'hello': 'world'
              >>> mocked_open.mock_calls
              [call('foobar.yaml', 'rt'),
              call().__enter__(),
              call().read(4096),
              call().read(4096),
              call().__exit__(None, None, None)]





              share|improve this answer



























                1














                You don't need to set __enter__ at all. Just pass in the data you want read as the read_data argument to mock_open():



                mocked_open = mock.mock_open(read_data='"hello":"world"')
                with mock.patch("yourmodule.open", mocked_open):
                result = load_yaml_file("foobar.yaml")


                Demonstration:



                >>> import yaml
                >>> def load_yaml_file(filename):
                ... with open(filename, 'rt') as f:
                ... data = yaml.load(f)
                ... return data
                ...
                >>> from unittest import mock
                >>> mocked_open = mock.mock_open(read_data='"hello":"world"')
                >>> with mock.patch("__main__.open", mocked_open):
                ... result = load_yaml_file("foobar.yaml")
                ...
                >>> print(result)
                'hello': 'world'
                >>> mocked_open.mock_calls
                [call('foobar.yaml', 'rt'),
                call().__enter__(),
                call().read(4096),
                call().read(4096),
                call().__exit__(None, None, None)]





                share|improve this answer

























                  1












                  1








                  1







                  You don't need to set __enter__ at all. Just pass in the data you want read as the read_data argument to mock_open():



                  mocked_open = mock.mock_open(read_data='"hello":"world"')
                  with mock.patch("yourmodule.open", mocked_open):
                  result = load_yaml_file("foobar.yaml")


                  Demonstration:



                  >>> import yaml
                  >>> def load_yaml_file(filename):
                  ... with open(filename, 'rt') as f:
                  ... data = yaml.load(f)
                  ... return data
                  ...
                  >>> from unittest import mock
                  >>> mocked_open = mock.mock_open(read_data='"hello":"world"')
                  >>> with mock.patch("__main__.open", mocked_open):
                  ... result = load_yaml_file("foobar.yaml")
                  ...
                  >>> print(result)
                  'hello': 'world'
                  >>> mocked_open.mock_calls
                  [call('foobar.yaml', 'rt'),
                  call().__enter__(),
                  call().read(4096),
                  call().read(4096),
                  call().__exit__(None, None, None)]





                  share|improve this answer













                  You don't need to set __enter__ at all. Just pass in the data you want read as the read_data argument to mock_open():



                  mocked_open = mock.mock_open(read_data='"hello":"world"')
                  with mock.patch("yourmodule.open", mocked_open):
                  result = load_yaml_file("foobar.yaml")


                  Demonstration:



                  >>> import yaml
                  >>> def load_yaml_file(filename):
                  ... with open(filename, 'rt') as f:
                  ... data = yaml.load(f)
                  ... return data
                  ...
                  >>> from unittest import mock
                  >>> mocked_open = mock.mock_open(read_data='"hello":"world"')
                  >>> with mock.patch("__main__.open", mocked_open):
                  ... result = load_yaml_file("foobar.yaml")
                  ...
                  >>> print(result)
                  'hello': 'world'
                  >>> mocked_open.mock_calls
                  [call('foobar.yaml', 'rt'),
                  call().__enter__(),
                  call().read(4096),
                  call().read(4096),
                  call().__exit__(None, None, None)]






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 25 '18 at 11:57









                  Martijn PietersMartijn Pieters

                  705k13324552281




                  705k13324552281



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53282809%2fpython-3-context-manager-mock-unit-test%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      這個網誌中的熱門文章

                      How to read a connectionString WITH PROVIDER in .NET Core?

                      Node.js Script on GitHub Pages or Amazon S3

                      Museum of Modern and Contemporary Art of Trento and Rovereto