Bird
Raised Fist0
Microservicessystem_design~25 mins

Unit testing services in Microservices - System Design Exercise

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Design: Unit Testing Framework for Microservices
Design focuses on the architecture of a unit testing framework and environment for microservices. It excludes integration or end-to-end testing frameworks.
Functional Requirements
FR1: Support writing and running unit tests for individual microservices
FR2: Isolate each microservice's logic from external dependencies during tests
FR3: Provide fast feedback with low latency test execution
FR4: Allow mocking of dependent services and databases
FR5: Integrate with CI/CD pipelines for automated testing
FR6: Support test result reporting and logs for debugging
Non-Functional Requirements
NFR1: Must handle up to 100 microservices independently
NFR2: Test execution latency should be under 5 seconds per test suite
NFR3: Availability of testing framework should be 99.9%
NFR4: Tests must not require network calls to other services or databases
Think Before You Design
Questions to Ask
❓ Question 1
❓ Question 2
❓ Question 3
❓ Question 4
❓ Question 5
❓ Question 6
Key Components
Test runner service
Mocking/stubbing library
Test isolation environment
Test result storage and reporting
CI/CD integration hooks
Design Patterns
Dependency injection for mocks
Test doubles (mocks, stubs, fakes)
Test isolation and sandboxing
Continuous testing in CI/CD
Parallel test execution
Reference Architecture
 +-------------------+       +---------------------+       +---------------------+
 | Microservice Code  | <---> | Unit Test Framework  | <---> | Mocking Library     |
 +-------------------+       +---------------------+       +---------------------+
          |                             |                             |
          |                             |                             |
          v                             v                             v
 +-------------------+       +---------------------+       +---------------------+
 | Test Runner       |       | Test Isolation Env  |       | Test Result Storage  |
 +-------------------+       +---------------------+       +---------------------+

Components
Test Runner
Jest, JUnit, or equivalent
Executes unit tests for each microservice and reports results
Mocking Library
Sinon.js, Mockito, or equivalent
Provides mocks and stubs to isolate microservice dependencies
Test Isolation Environment
Docker containers or in-memory sandboxes
Ensures tests run isolated from external services and databases
Test Result Storage
Elasticsearch, or CI/CD test reporting tools
Stores test results and logs for analysis and debugging
CI/CD Integration
Jenkins, GitHub Actions, GitLab CI
Triggers tests automatically on code changes and collects results
Request Flow
1. Developer writes unit tests using the mocking library to replace dependencies.
2. Test runner executes the tests inside the isolated environment to prevent external calls.
3. Mocks simulate dependent services and databases during test execution.
4. Test runner collects pass/fail results and logs.
5. Results are stored in the test result storage system.
6. CI/CD pipeline triggers test runs on code commits and fetches results for reporting.
7. Developers review test reports and debug failures using logs.
Database Schema
Entities: - TestCase: id, microservice_id, name, description, code - TestRun: id, test_case_id, status (pass/fail), start_time, end_time, logs - Microservice: id, name, language, repository_url Relationships: - Microservice 1:N TestCase - TestCase 1:N TestRun
Scaling Discussion
Bottlenecks
Test execution time grows with number of microservices and test cases
Resource contention in test isolation environments
Storage size and query performance for test results
Mocking complexity for highly coupled services
Solutions
Run tests in parallel across multiple isolated containers or machines
Use lightweight sandboxing or in-memory mocks to reduce resource use
Archive old test results and optimize indexing for fast queries
Encourage loose coupling and clear interfaces to simplify mocking
Interview Tips
Time: Spend 10 minutes clarifying requirements and constraints, 20 minutes designing components and data flow, 10 minutes discussing scaling and trade-offs, 5 minutes summarizing.
Importance of isolating microservices for unit testing
Use of mocks and stubs to replace dependencies
Integration with CI/CD for automated testing
Handling test result storage and reporting
Scaling tests with parallel execution and resource management

Practice

(1/5)
1. What is the main purpose of unit testing in microservices?
easy
A. To deploy the service automatically
B. To test the entire system end-to-end
C. To monitor service performance in production
D. To test small parts of a service independently

Solution

  1. Step 1: Understand unit testing scope

    Unit testing focuses on testing small, isolated parts of a service, not the whole system.
  2. Step 2: Differentiate from other testing types

    End-to-end tests check the entire system, while unit tests check individual components.
  3. Final Answer:

    To test small parts of a service independently -> Option D
  4. Quick Check:

    Unit testing = small parts tested independently [OK]
Hint: Unit tests check small parts, not whole system [OK]
Common Mistakes:
  • Confusing unit tests with integration or end-to-end tests
  • Thinking unit tests deploy or monitor services
  • Believing unit tests require full system setup
2. Which of the following is the correct way to mock a database call in a unit test for a microservice?
easy
A. Replace the database call with a mock object returning fixed data
B. Call the real database and check results
C. Skip the database call and do nothing
D. Use the production database credentials in the test

Solution

  1. Step 1: Understand mocking purpose

    Mocks replace real dependencies to isolate the unit under test and control test data.
  2. Step 2: Identify correct mocking practice

    Replacing the database call with a mock object returning fixed data allows testing without real DB access.
  3. Final Answer:

    Replace the database call with a mock object returning fixed data -> Option A
  4. Quick Check:

    Mocking = replace real calls with controlled fake ones [OK]
Hint: Mocks replace real calls with fake data in tests [OK]
Common Mistakes:
  • Using real database in unit tests
  • Skipping important calls without replacement
  • Using production credentials in tests
3. Consider this Python unit test snippet for a microservice method that fetches user data:
def test_get_user_data(mocker):
    mock_db = mocker.patch('service.database.get_user')
    mock_db.return_value = {'id': 1, 'name': 'Alice'}
    result = service.get_user_data(1)
    assert result['name'] == 'Alice'
What will this test verify?
medium
A. That get_user_data returns user name 'Alice' using mocked DB
B. That the real database returns user Alice
C. That the database call is skipped entirely
D. That the service raises an error for user 1

Solution

  1. Step 1: Analyze mocking effect

    The database call get_user is replaced by a mock returning fixed user data with name 'Alice'.
  2. Step 2: Understand test assertion

    The test checks if get_user_data returns a result with name 'Alice', confirming it uses the mocked data.
  3. Final Answer:

    That get_user_data returns user name 'Alice' using mocked DB -> Option A
  4. Quick Check:

    Mocked DB returns Alice, test checks service uses it [OK]
Hint: Mock return_value sets test data; assert checks service output [OK]
Common Mistakes:
  • Assuming real DB is called
  • Thinking database call is skipped without replacement
  • Expecting error instead of valid data
4. A developer writes this unit test for a microservice method:
def test_process_order():
    result = process_order(123)
    assert result == 'Success'
But the test fails because process_order calls an external payment service. What is the best fix?
medium
A. Rewrite process_order to not call payment service
B. Add a mock for the external payment service call
C. Run the test only when payment service is available
D. Remove the assertion to avoid failure

Solution

  1. Step 1: Identify external dependency issue

    process_order calls an external service, causing test failure due to dependency.
  2. Step 2: Apply mocking to isolate test

    Mocking the external payment service call isolates the unit test and avoids real external calls.
  3. Final Answer:

    Add a mock for the external payment service call -> Option B
  4. Quick Check:

    Mock external calls to isolate unit tests [OK]
Hint: Mock external services to avoid test failures [OK]
Common Mistakes:
  • Removing assertions instead of fixing dependencies
  • Running tests only when external services are up
  • Changing production code to fix tests
5. You want to unit test a microservice method that calls two other services: a user service and an inventory service. Which approach best ensures your unit test is reliable and fast?
hard
A. Skip testing this method because it depends on other services
B. Call both real services during the test to check integration
C. Mock both user and inventory service calls with fixed responses
D. Test only the user service call and ignore inventory service

Solution

  1. Step 1: Understand unit test isolation

    Unit tests should isolate the method by mocking external service calls to avoid flakiness and slowness.
  2. Step 2: Apply mocks to all external dependencies

    Mocking both user and inventory service calls ensures the test is reliable and fast without real network calls.
  3. Final Answer:

    Mock both user and inventory service calls with fixed responses -> Option C
  4. Quick Check:

    Mock all external calls for reliable, fast unit tests [OK]
Hint: Mock all external services for isolated unit tests [OK]
Common Mistakes:
  • Calling real services in unit tests
  • Skipping tests due to dependencies
  • Partially mocking dependencies leading to flaky tests