Darth
Darth

Reputation: 229

How to Unit Test Function opening a json file?

The function below opens and loads a Json file. My question is whats the best approach to test it?

def read_file_data(filename, path):
    os.chdir(path)
    with open(filename,  encoding="utf8") as data_file:
        json_data = json.load(data_file)
    return json_data

filename and path are passed in as sys.argv's.

I figured that i would need sample data in my test case for a start but not sure how i would actually use it to test the function

class TestMyFunctions(unittest.TestCase):
    def test_read_file_data(self):
        sample_json = {
                      'name' : 'John',
                      'shares' : 100,
                      'price' : 1230.23
                      }

Any pointer will be appreciated.

Upvotes: 4

Views: 15054

Answers (3)

Ahmed Alhallag
Ahmed Alhallag

Reputation: 311

  1. Check these answers first: How to use mock_open with json.load()?

  2. some of the answers are using json.dump instead of json.dumps interchagebly, which is wrong.

  3. read, open, load, as stated are from Standard Python Library, already been tested, so you'd rather think about testing some actual column's values/types or some rows in your json file instead, and if you did that, this would not be a unit test anymore, it'll be an integration test since you have dependencies coupled to your method (json data in this case) which would be meaningless to purposely decouple them via mocking.

Upvotes: 0

bmjrowe
bmjrowe

Reputation: 336

As stated above you do not need to retest the standard python library code works correctly, so by creating a hard coded file as also stated, you are defeating the point of a unit test by testing outside of your unit of code.

Instead a correct approach would be to mock the opening of the file using pythons mocking framework. And thus test that your function returns the json that's read in correctly.

e.g.

from unittest.mock import patch, mock_open
import json

class TestMyFunctions(unittest.TestCase):


@patch("builtins.open", new_callable=mock_open,
       read_data=json.dumps({'name' : 'John','shares' : 100,
                        'price' : 1230.23}))
def test_read_file_data(self):
    expected_output = {
                  'name' : 'John',
                  'shares' : 100,
                  'price' : 1230.23
                  }
    filename = 'example.json'
    actual_output = read_file_data(filename, 'example/path')

    # Assert filename is file that is opened
    mock_file.assert_called_with(filename)

    self.assertEqual(expected_output, actual_output)

Upvotes: 5

Jeremy Barnes
Jeremy Barnes

Reputation: 662

I think that what you would want to do would be to make the JSON file, hardcode an in memory version of that JSON file and assert equals between the two.

Based on your code:

class TestMyFunctions(unittest.TestCase):
    def test_read_file_data(self):
        import json
        sample_json = {
                      'name' : 'John',
                      'shares' : 100,
                      'price' : 1230.23
                      }
        sample_json = json.dump(sample_json, ensure_ascii=False)
        path = /path/to/file
        filename = testcase.json
        self.assertEqual(read_file_data(filename, path), sample_json)

Upvotes: 1

Related Questions