Python: Unit Testing

(Last Updated On: )

This post focus’ on common hurdles when trying to do unit testing.

Testing Values During Run

You add the following line to anywhere you want to pause the unit test to check values.

  1. import pdb
  2. pdb.set_trace()

How to Patch a Function

  1. from unittest.mock import path
  2.  
  3. @patch('src.path.to.file.my_function')
  4. @path('src.path.to.file.my_function_add')
  5. def test_some_function(mock_my_function_add, mock_my_function):
  6. mock_function_add.return_value = <something>
  7. .......

How to Patch a Function With No Return Value

  1. from unittest.mock import patch
  2.  
  3. def test_some_function():
  4. with(patch('src.path.to.file.my_function'):
  5. ...

How to Patch a Function With 1 Return Value

  1. from unittest.mock import patch
  2.  
  3. def test_some_function():
  4. with(patch('src.path.to.file.my_function', MagicMock(return_value=[<MY_VALUES>])):
  5. ...

How to Patch a Function With Multiple Return Value

  1. from unittest.mock import patch
  2.  
  3. def test_some_function():
  4. with(patch('src.path.to.file.my_function', MagicMock(side-effect=[[<MY_VALUES>], [<OTHER_VALUES>]])):
  5. ...

How to Create a Test Module

  1. from unittest import TestCase
  2.  
  3. class MyModule(TestCase):
  4. def setUp(self):
  5. some_class.my_variable = <something>
  6. ... DO OTHER STUFF
  7. def test_my_function(self):
  8. ... DO Function Test Stuff

How to Patch a Method

  1. patch_methods = [
  2. "pyodbc.connect"
  3. ]
  4.  
  5. for method in patch_methods:
  6. patch(method).start()

How to create a PySpark Session

Now once you do this you can just call spark and it will set it.

  1. import pytest
  2. from pyspark.sql import SparkSession
  3.  
  4. @pytest.fixture(scope='module')
  5. def spark():
  6. return (SparkSession.builder.appName('pyspark_test').getOrCreate())

How to Create a Spark SQL Example

  1. import pytest
  2. from pyspark.sql import SparkSession, Row
  3. from pyspark.sql.types import StructType, StructField, StringType
  4.  
  5. @pytest.fixture(scope='module')
  6. def spark():
  7. return (SparkSession.builder.appName('pyspark_test').getOrCreate())
  8.  
  9. def test_function(spark):
  10. query = 'SELECT * FROM SOMETHING'
  11. schema = StructType([
  12. StructField('column_a', StringType()),
  13. StructField('column_b', StringType()),
  14. StructField('column_c', StringType()),
  15. ])
  16.  
  17. data = [Row(column_a='a', column_b='b', column_c='c')]
  18. table = spark.createDataFrame(data, schema=schema)
  19. table.createOrReplaceTempView('<table_name>')
  20. df = spark.sql(query).toPandas()
  21.  
  22. assert not df.empty
  23. assert df.shape[0] == 1
  24. assert df.shape(1) == 5
  25.  
  26. spark.catalog.dropTempView('<table_name>')

How to Mock a Database Call

First let’s assume you have an exeucte sql function

  1. def execute_sql(cursor, sql, params):
  2. result = cursor.execute(sql, params).fetchone()
  3. connection.commit()
  4. return result

Next in your unit tests you want to test that funciton

  1. def test_execute_sql():
  2. val = <YOUR_RETURN_VALUE>
  3. with patch('path.to.code.execute_sql', MagicMock(return_value=val)) as mock_execute:
  4. return_val = some_other_function_that_calls_execute_sql(....)
  5. assert return_val == val

If you need to close a cursor or DB connection

  1. def test_execute_sql():
  2. val = <YOUR_RETURN_VALUE>
  3. mock_cursor = MagicMock()
  4. mock_cursor.configure_mock(
  5. **{
  6. "close": MagicMock()
  7. }
  8. )
  9. mock_connection = MagicMock()
  10. mock_connection.configure_mock(
  11. **{
  12. "close": MagicMock()
  13. }
  14. )
  15.  
  16. with patch('path.to.code.cursor', MagicMock(return_value=mock_cursor)) as mock_cursor_close:
  17. with patch('path.to.code.connection', MagicMock(return_value=mock_connection)) as mock_connection_close:
  18. return_val = some_other_function_that_calls_execute_sql(....)
  19. assert return_val == val

How to Mock Open a File Example 1

  1. @patch('builtins.open", new_callable=mock_open, read_data='my_data')
  2. def test_file_open(mock_file):
  3. assert open("my/file/path/filename.extension").read() == 'my_data'
  4. mock_file.assert_called_with("my/file/path/filename.extension")
  5.  
  6. val = function_to_test(....)
  7. assert 'my_data' == val

How to Mock Open a File Example 2

  1. def test_file_open():
  2. fake_file_path = 'file/path/to/mock'
  3. file_content_mock = 'test'
  4. with patch('path.to.code.function'.format(__name__), new=mock_open(read_data=file_content_mock)) as mock_file:
  5. with patch(os.utime') as mock_utime:
  6. actual = function_to_test(fake_file_path)
  7. mock_file.assert_called_once_with(fake_file_path)
  8. assertIsNotNone(actual)

Compare DataFrames

  1. def as_dicts(df):
  2. df = [row.asDict() for row in df.collect()]
  3. return sorted(df, key=lambda row: str(row))
  4.  
  5. assert as_dicts(df1) == as_dicts(df2)