Unit Testing in Python - Interview Questions and Answers
Unit testing involves testing individual components (units) of a program to ensure they perform as expected.
It helps identify bugs early, ensures code reliability, simplifies refactoring, and improves development speed.
unittest
is Python's built-in module for writing and running unit tests using the xUnit style.
import unittest
def add(x, y):
return x + y
class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == '__main__':
unittest.main()
Test method names should start with test_
, so the test runner can detect and run them automatically.
assertEqual(a, b)
checks ifa == b
.assertTrue(x)
checks ifx
isTrue
.
with self.assertRaises(ValueError):
int('abc')
@unittest.skip("Skipping this test temporarily")
def test_temp(self):
...
setUp()
is run before each test method and is used to set initial conditions.
It’s executed after each test method for cleanup activities like closing files or database connections.
By placing them in classes that inherit from unittest.TestCase
.
Use unittest.main()
in the script, or run it with python -m unittest filename.py
.
It's not recommended. Focus on testing public interfaces that use private methods internally.
self.assertIsNone(func())
It measures how much of your code is tested by your test suite.
Popular tools include coverage.py
and pytest-cov
.
Yes, use the -k
flag with test name patterns when using pytest
.
Use the warnings
module or decorators like @pytest.mark.filterwarnings
.
assertAlmostEqual
is used for comparing floating-point values with a tolerance.
Fixtures are pre-test setups like sample data or configurations needed for the test.
@patch
is used to replace a method, class, or object with a mock during the test execution.
A mock is a simulated object that mimics the behavior of real objects in controlled ways for testing purposes.
from unittest.mock import patch
@patch('module.function_name')
def test_mock_func(mock_func):
mock_func.return_value = 'mocked'
assert module.function_name() == 'mocked'
Mock
: Base class for mocks.MagicMock
: Subclass with magic methods like__len__
,__getitem__
, etc.patch
: Context manager or decorator to replace objects during testing.
It allows setting a sequence of return values or even exceptions to be raised.
mock_object.assert_called()
mock_object.assert_called_with(arg1, arg2)
Use tools like pytest-xdist
to run tests with pytest -n auto
.
It helps run a test multiple times with different input while keeping each as a separate sub-test case.
Use libraries like parameterized
or pytest.mark.parametrize
with pytest
.
Not typically. Unit tests focus on correctness. Use benchmarks or profiling tools for performance testing.
- Unit testing: Tests individual units in isolation.
- Integration testing: Tests how multiple units work together.
Each test should run independently without relying on shared state or other tests.
Each test should run independently without relying on shared state or other tests.
Use libraries like freezegun
or mock datetime.now()
.
from unittest.mock import mock_open, patch
with patch('builtins.open', mock_open(read_data='data')) as mock_file:
open('file.txt').read()
Automatically locating and running all test files using a pattern, e.g., python -m unittest discover
.
A collection of test cases or test classes grouped together.
mock_obj.method.assert_called_once()
mock_obj.method.assert_called_with(args)
CI/CD runs automated tests (including unit tests) on every code change to ensure code quality.
A test that sometimes passes and sometimes fails without any changes in code or environment.
By running the same test multiple times or using tools like pytest-rerunfailures
.
Mock external requests (using requests-mock
) and test your handler’s behavior/response codes.
@patch('requests.get')
def test_get(mock_get):
mock_get.return_value.status_code = 200
...
Use asyncio.run()
in tests or pytest-asyncio
to test async methods.
@patch.dict(os.environ, {"API_KEY": "test-key"})
def test_env():
...
Use self.assertLogs(logger_name, level)
context manager.
Temporarily replacing an object or method during runtime to alter its behavior in tests.
from io import StringIO
from contextlib import redirect_stdout
f = StringIO()
with redirect_stdout(f):
print("hello")
assert "hello" in f.getvalue()
Use test databases or in-memory databases like SQLite with setup and teardown.
Use mocks or join threads inside the test to ensure behavior is predictable.
- Test one thing at a time.
- Use mocks for external dependencies.
- Keep tests independent.
- Make tests fast and repeatable.
- Use meaningful test names.
Yes, test the decorated function’s behavior or the decorator logic directly if needed.
A development approach where tests are written before writing the actual code.
with self.assertWarns(UserWarning):
warnings.warn("Deprecated")
They replace real objects with simplified versions like stubs, mocks, and fakes for testing.
Tests that run the same logic with different inputs, usually using a decorator to iterate.
@pytest.fixture
def sample_data():
return {'name': 'John'}
def test_name(sample_data):
assert sample_data['name'] == 'John'
Yes, using parameterization or external test data files (JSON, CSV, etc.).
Simulating DB interactions by mocking the ORM methods or queries.
Yes, but you might need to refactor the legacy code to make it testable.
Use a structured folder hierarchy, consistent naming, and grouping via test classes or modules.
Tutorials
Random Blogs
- The Ultimate Guide to Data Science: Everything You Need to Know
- How AI Companies Are Making Humans Fools and Exploiting Their Data
- Python Challenging Programming Exercises Part 1
- Transforming Logistics: The Power of AI in Supply Chain Management
- Top 10 Knowledge for Machine Learning & Data Science Students
- Convert RBG Image to Gray Scale Image Using CV2
- Why to learn Digital Marketing?
- 10 Awesome Data Science Blogs To Check Out
- Downlaod Youtube Video in Any Format Using Python Pytube Library
- AI in Cybersecurity: The Future of Digital Protection