2

This is function to get version and using with open to read file from file path location.

def get_version(self):
    try:
        with open("file_path") as openfile:
            for line in openfile:
                sline = line.split()
                for row, column in enumerate(sline):
                    if column == "version=":
                        version = sline[row+1].strip('"')
    return version
3
  • And also this is only a part of your function because I don't see except block. Commented Feb 12, 2020 at 8:11
  • Hi @sid, and welcome! It looks like there are a few similar questions, about unit testing builtin functions such as open(). Have a look here as a starting point. Commented Feb 12, 2020 at 8:17
  • except block is handled in UT part Commented Feb 12, 2020 at 8:22

2 Answers 2

7

You can use unittest.mock.mock_open(mock=None, read_data=None) to mock the open function.

E.g.

main.py:

class MyClass:
    def get_version(self):
        version = ''
        with open("file_path") as openfile:
            for line in openfile:
                sline = line.split()
                for row, column in enumerate(sline):
                    if column == "version=":
                        version = sline[row+1].strip('"')

        return version

test_main.py:

from main import MyClass
import unittest
from unittest.mock import mock_open, patch


class TestMain(unittest.TestCase):
    def test_get_version(self):
        m = mock_open(read_data='version= 1.0.0')
        with patch('builtins.open', m) as mocked_open:
            myclass_instace = MyClass()
            version = myclass_instace.get_version()
            self.assertEqual(version, '1.0.0')
            m.assert_called_with('file_path')


if __name__ == '__main__':
    unittest.main()

unit test results with 100% coverage:

.
----------------------------------------------------------------------
Ran 1 test in 0.011s

OK
Name                                      Stmts   Miss  Cover   Missing
-----------------------------------------------------------------------
src/stackoverflow/60183706/main.py           10      0   100%
src/stackoverflow/60183706/test_main.py      14      0   100%
-----------------------------------------------------------------------
TOTAL                                        24      0   100%

Python version: Python 3.7.5

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

1 Comment

I have used your answer with Python 3.6, but it doesn't work perfectly may be because read_data doesn't work with readline(). So I have written an other answer where I have added methods __iter__ and __next__ to the mock object obtains by mock_open. However I have upvoted your answer because it has been very useful for me.
0

You can use mock_open helper function:

unittest.mock.mock_open(mock=None, read_data=None)

A helper function to create a mock to replace the use of open(). It works for open() called directly or used as a context manager.

Previous sentences come from the documentation of the module unittest.mock

Because the production method get_version() reads a file by a for loop you have to define methods __iter__ and __next__ for the mock object instantiated by mock_open as suggested by this post.

So if your production code is stored in the file my_class.py as below:

class MyClass:
    def get_version(self):
        version = ''
        with open("file_path") as openfile:
            for line in openfile:
                sline = line.split()
                for row, column in enumerate(sline):
                    if column == "version=":
                        version = sline[row+1].strip('"')
        return version

a possible test which uses the helper function mock_open could be the following:

from my_class import MyClass
import unittest
from unittest.mock import mock_open, patch

class TestMyClass(unittest.TestCase):
    def test_get_version(self):
        # by the argument read_data set the content of the file
        mocked_open = mock_open(read_data='version= 2.1\nsecond line\n')
        EXPECTED_VERSION = "2.1"
        mocked_open_instance = mocked_open.return_value
        mocked_open_instance.__iter__ = lambda self: self
        mocked_open_instance.__next__ = lambda self: next(iter(self.readline, ''))
        with patch('builtins.open', mocked_open):
            sut = MyClass()
            version = sut.get_version()
            self.assertEqual(EXPECTED_VERSION, version)
            mocked_open.assert_called_with('file_path')
            # for the file content 'version= 2.1\nsecond line\n' the readline function must be called 3 times
            self.assertEqual(3, mocked_open_instance.readline.call_count)

if __name__ == '__main__':
    unittest.main()

Version of Python used is: Python 3.6.

Comments

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.