Verify integration of two components: UserService and EmailService
Preconditions (3)
✅ Expected Result: EmailService sends a welcome email to the new user email address
Jump into concepts and practice - no test required
import pytest class EmailService: def __init__(self): self.sent_emails = [] def send_email(self, to_address: str, content: str): self.sent_emails.append({'to': to_address, 'content': content}) class UserService: def __init__(self, email_service: EmailService): self.email_service = email_service def register_user(self, email: str): # Imagine user registration logic here welcome_message = f"Welcome, {email}!" self.email_service.send_email(email, welcome_message) @pytest.fixture def email_service(): return EmailService() @pytest.fixture def user_service(email_service): return UserService(email_service) def test_user_registration_sends_welcome_email(user_service, email_service): test_email = 'testuser@example.com' user_service.register_user(test_email) assert len(email_service.sent_emails) == 1, "Expected one email to be sent" sent_email = email_service.sent_emails[0] assert sent_email['to'] == test_email, f"Email sent to {sent_email['to']} instead of {test_email}" assert 'Welcome' in sent_email['content'], "Email content does not contain 'Welcome'"
This test checks that when UserService.register_user is called, it uses the EmailService to send a welcome email.
We create real instances of both services to verify their integration, not mocks, so we test the actual collaboration.
Fixtures set up the services cleanly for reuse.
Assertions check that exactly one email was sent, to the correct address, and that the content includes the word 'Welcome'.
This shows how integration tests verify components working together, not just isolated units.
Now add data-driven testing with 3 different user emails to verify welcome emails are sent correctly for each.
add and multiply are used together in one test.def test_process_order():
order = create_order(5)
result = process_payment(order)
assert result == 'Success'create_order and then process_payment with the order. It asserts the result equals 'Success'.process_payment(order) returns 'Success', the assertion passes and the test passes. Otherwise, it fails.def test_user_login():
user = create_user('alice')
assert login(user) == True
assert logout(user) = Truefetch_data() returns data list, and process_data(data) filters it. Why is an integration test combining both important?fetch_data() gets data, process_data(data) filters it. Testing them together checks real interaction.process_data handles actual data from fetch_data, catching issues missed by isolated tests.