Advanced Mocking in Unittest
In the previous chapter, we saw the importance of using Mock in testing. Now, let's take a closer look at the different capabilities and clarify any aspects that were unclear.
Introduction to MagicMock
MagicMock is an incredibly versatile implementation of Mock that supports magic methods. You can use it to mimic the behavior of complex objects in your tests as we saw in previous chapter.
python991234567891011121314151617from unittest.mock import MagicMockimport unittestclass BankAccount:def __init__(self, id):self.id = idself.balance = self.get_account_balance(id)def get_account_balance(self, id):# Simulates a database callpassclass TestBankAccount(unittest.TestCase):def test_balance_retrieval(self):account = BankAccount(1)account.get_account_balance = MagicMock(return_value=1000)self.assertEqual(account.balance, 1000)
In this example, MagicMock is used to simulate the get_account_balance
method, which would typically retrieve data from a database.
Using mock.patch
@mock.patch is used for temporarily replacing the real implementations of objects in your code.
Imagine a function that checks user credentials against a database. You can use mock.patch to avoid hitting the actual database:
python9912345678910111213from unittest.mock import patchimport unittestdef authenticate(username, password):# Assume this function checks credentials against a databasepassclass TestAuthentication(unittest.TestCase):@patch('module_containing.authenticate')def test_login(self, mock_auth):mock_auth.return_value = Trueresponse = authenticate('user', 'pass')self.assertTrue(response)
Mocking with Context Manager
At times, it's preferable to employ patch() as a context manager instead of a decorator, particularly when:
you need to mock an object for just a portion of the test;
or when excessive use of decorators or parameters is reducing the clarity of your tests.
python991234567891011121314151617from unittest.mock import patchimport unittestclass BankAccount:def __init__(self, id):self.id = idself.balance = self.get_account_balance(id)def get_account_balance(self, id):# Simulates a database callreturn 100 # Dummy return value for demonstrationclass TestBankAccount(unittest.TestCase):def test_balance_retrieval(self):with patch('__main__.BankAccount.get_account_balance', return_value=1000):account = BankAccount(1)self.assertEqual(account.balance, 1000)
Pytest Monkey Patch
The monkeypatch fixture in Pytest lets you temporarily modify classes, modules, or environments during a test.
python9123456789import osimport pytestdef test_api_url(monkeypatch):# Set the API_URL environment variable to a test URLmonkeypatch.setenv('API_URL', 'https://testapi.com')# Now check that the environment variable was set correctlyassert os.environ['API_URL'] == 'https://testapi.com'
The monkeypatch fixture allows you to safely modify and manage the environment during the test without causing side effects outside the test scope.
1. Which of the following code snippets correctly mocks the get_balance method to return 500?
2. What does the following test check?
Bedankt voor je feedback!
Vraag AI
Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.