Backend Handbook
Leapwise
  • 👋Introduction
  • Software Design Principles & Clean Code
    • Atomicity
    • Modularity
    • Hierarchy
    • Loose coupling
    • Asynchronous programming
  • Development Practices
    • JavaDocs
    • Technical Debt
    • Testing Guidelines
      • The Importance of Test Automation
      • The Testing Pyramid
        • Unit Tests
        • Integration Tests
        • End-to-End Tests
      • Mutation Testing
      • Contract Tests
        • REST Controller Contract testing
        • OpenAPI Contract testing
      • Testing Frameworks
        • JUnit 5
        • Testcontainers
        • Mockito
      • Writing Clean Tests - Best Practices
    • Common library
    • Generic CRUD
    • Update Facade
  • Development Tools & Environment
    • Monitoring
    • Performance tuning
    • Multi-tenancy & Configuration Management
    • Git practices
    • CI/CD
    • Maven
  • Project Management
    • Jira
    • Confluence documentation
    • SCRUM
    • Our ways of working
  • LIFE AT LEAPWISE
    • Introduction
    • Who are we?
    • What do we do?
    • Our values
    • Hiring process
      • Hiring: A Mid Frontend Developer's Point of View
    • Benefits we offer
    • Onboarding process
      • Onboarding: A Senior Digital Marketing Specialist's perspective
    • Mentorship program
    • Career development
      • Trainings & certificates we offer
      • Career development: A Senior Software Developer's Insight
    • Community building
    • Juniorship
    • First-hand info from our first team member
    • Join our team
Powered by GitBook
LogoLogo

Company

  • About
  • Culture
  • Services

Insights

  • Leapwise Newsletter
  • Blog

© Leapwise

On this page
  • Fakes
  • Mocks
  • Stubs
  • Comparison

Was this helpful?

  1. Development Practices
  2. Testing Guidelines
  3. The Testing Pyramid

Unit Tests

Unit testing is a technique for testing the smallest units of an application to ensure they work as intended. The smallest unit of an application depends on the language: in functional languages, it's a function, while in object-oriented paradigms, it's a method or a class. The requirements for unit tests are that they should be isolated, fast, and consistent, meaning they should give the same result every time they are executed.

When writing unit tests, especially for components that interact with external systems or complex dependencies, isolating the unit under test is important. This is where fakes, mocks, and stubs come into play. The more complex a project is the greater the need for using fakes, mocks, and stubs for testing. Testing applications with complex dependencies can be tricky. Fakes, mocks, and stubs make this process easier and improve the quality, reliability, and simplicity of tests.

Fakes

Fakes are objects that have working implementations but are simpler compared to the production versions. These simplified versions are often used for integration testing to avoid the need for complex setups or external dependencies. For instance, an in-memory database (e.g. H2) can be used to store data rather than an actual production database implementation, providing quicker, simpler, and less resource-intensive tests.

Fakes are also a tool for prototyping and experimentation, allowing developers to defer decisions about final deployments, such as database design. Fakes help simulate real-world complex scenarios effectively and efficiently.

Mocks

Mocks are specialized objects that record the calls they receive, enabling the verification of interactions during tests. They are used when you need to confirm that certain methods were called, without invoking actual production code.

For example, a mock mail service such as shown below can be used to ensure that the sending method was called and the necessary functionality was tested, without actually sending emails during the test execution.

Mocks are prepared with expectations to ensure consistent and deterministic behavior during tests. They do not execute real logic but instead focus on verifying that a specific interaction occurred. In unit tests, mocks can replace dependencies, allowing the testing of business logic in isolation. Mocking frameworks and libraries often manage the lifecycle of mock objects, making it easier for developers to integrate them into their test suites and ensure thorough test coverage.

Stubs

Stubs are objects that return predefined data in response to calls made during tests. They are particularly useful when you cannot or do not want to use real objects that might have undesirable side effects or are not available.

For example, instead of querying a database, a stub can return fixed data, ensuring that tests are consistent and predictable. Stubs provide a controlled environment for testing by delivering specific responses without performing any real logic. Unlike mocks, stubs do not record interactions and cannot return different values based on varying inputs. They are simple and effective for ensuring that certain conditions are met during tests without the overhead of managing real dependencies.

Comparison

Fakes
Mocks
Stubs

Implementation

Simplified implementation of certain functionality.

Pre-programmed with expectations providing deterministic behavior.

Provide canned responses or predefined behavior without real implementation.

Verify interactions

Do not verify interactions.

Configured to verify the occurrence of expected interaction.

Do not verify interactions.

Flexibility

No flexibility during tests.

Very flexible as multiple expectations and responses can be configured.

Less flexible in terms of behavior since they provide predefined responses.

PreviousThe Testing PyramidNextIntegration Tests

Last updated 11 months ago

Was this helpful?

Page cover image