Mock Testing

Mocking external components. Source: SoapUI 2019.
Mocking external components. Source: SoapUI 2019.

Mock testing is an approach to unit testing that lets you make assertions about how the code under test is interacting with other system modules. In mock testing, the dependencies are replaced with objects that simulate the behaviour of the real ones. The purpose of mocking is to isolate and focus on the code being tested and not on the behaviour or state of external dependencies.

Let's say, a notification service triggers an email service. We don't want to send emails each time we run a notification test. However, we want to verify that the email-sending service is called. Such a service can be replaced with a mock object.

Discussion

  • Where is mock testing useful?
    Common uses of mocking. Source: SoapUI 2019.
    Common uses of mocking. Source: SoapUI 2019.

    Mocking is generally useful during unit testing so that external dependencies are no longer a constraint to the unit under test. Often those dependencies may themselves be under development. Without mocking, if a test case fails, it will be hard to know if the failure is due to our code unit or due to dependencies. Mocking therefore speeds up development and testing by isolating failures.

    Other reasons to mock dependencies is to avoid slow network calls or call third-party APIs. Mocking also enables product demos and evaluations. All units of a project can progress in parallel without waiting for everyone to be ready. Thus, testing can start early.

    Code that have side effects should be called only in production. Examples include charging a credit card or sending a notification. Mocking is useful to validate such calls without the side effects.

    Mocking avoids duplicating test code across similar tests. The task of verifying method or API calls from our module can be delegated to the mock.

  • Could you give some examples of mock testing?
    Use of the Mock Network Provider avoids external API calls. Source: Agostini 2017.
    Use of the Mock Network Provider avoids external API calls. Source: Agostini 2017.

    Let's say, an Order class fulfils orders by calling a Warehouse class. The latter knows the current inventory. If we are unit testing Order class, we mock the Warehouse. We don't care about testing Warehouse right now. But since it's a dependency for Order, we mock it. Our mock object can be called WarehouseMock.

    A mock object provides a pseudo implementation of the same interface as the real object. Those calling it are unaware that it's a mock. Thus, to the Order class, WarehouseMock looks the same as Warehouse. This is just what we need to unit test Order class.

    Another example is about an application calling an external API to get information about movies. Instead of making real calls, this can be mocked so that when API calls are made, the mock object will simply read and respond with test data from a local file system.

  • Does mocking require developers to modify their codebase?

    If your code uses static objects or singletons, then it's difficult to do mocking. In such cases, it's better to refactor code. Otherwise, in general, mocking doesn't require you to modify the codebase. In fact, dependency injection is the usual way in which objects should be created. Dependencies become visible in the constructors and other methods. These dependencies can therefore be easily replaced during testing with mock objects. This can be configured either in code or via a configuration file.

  • How is mock testing different from traditional unit testing?
    Mocks replace actual Door and Window objects. Source: Lipski 2017.
    Mocks replace actual Door and Window objects. Source: Lipski 2017.

    In traditional unit testing, unit tests do assertions about states expected of either the system under test or its dependencies. With mock testing, no assertions are required from the unit tests themselves. Assertions are done by the mock objects. These objects are initialized in advance about what method calls are expected and how they should respond.

    While unit tests are more about state-based verification, mock testing is more about behaviour-based verification. For example, let's assume that SecurityCentral is being tested. It depends on Door. When SecurityCentral activates full security, unit testing will verify the final state of Door, that it's closed. Mocking would instead verify that the correct method was invoked with expected arguments, such as Door.close(). Mocks register the calls they receive so these can be asserted.

  • What are the common types of mock testing?

    In proxy-based mocking, a proxy object is used instead of the original object. The proxy may handle all calls to the original object or selectively forward some calls. Mock frameworks such as EasyMock, JMock, Mockito offer this type of mocking. However, there may be limitations in terms of proxying static/private/final methods or a final class.

    In classloader-remapping-based mocking, a class loader remaps the reference. Thus, it loads the mock object rather than the original one. Mock frameworks such as JMockit and PowerMock support this. This overcomes the limits of proxy-based mocking.

    In Swift language, one developers blogged that he uses two ways to do mocking: instance injection and configuration injection. The former is simpler but it can't handle static objects.

  • What are some best practices for mock testing?

    Here are some best practices for mocking:

    • Only mock types that you own: External types have dependencies on their own. They might even change their behaviour in a future version. Instead, create an adapter and mock that adapter.
    • Don't mock values: Values should not be mocked. Mocking aims to make the relationships and interactions between objects visible. Getting a value is not an interaction.
    • Avoid mocking concrete classes: Relationships are easier to see via interfaces rather than concrete classes. We might end up mocking some methods but forget others. Mock roles, not objects.
    • Don't mock everything: This is an anti-pattern. If everything is mocked, we may end up testing something quite different from production system.
    • Use integration tests: When testing multiple modules or if you're interested in data coming from an external database, you should do integration testing rather than mocking.
    • Negative tests: Use mocks to simulate errors and test error handling. Use mocks to verify that some methods/APIs are not called.
  • What are some mocking frameworks?

    While it's possible to manually write mock objects, mocking frameworks simplify the task. Mockito is an open source testing framework for Java. Mockito is claimed to be the one of the popular ones.

    JustMock and MOQ package are useful for .NET developers. . There's also JustMock Lite when dealing with loosely coupled code. Wiremock is suitable for mocking HTTP-based APIs.

    For C++ developers, there's TypeMock and Google Mock. The latter is part of GoogleTest. TypeMock uses a templating approach to create mocks whereas Google Mock uses inheritance.

    Other frameworks include EasyMock, JMock, JMockit, and PowerMock. Ease of use, maintainability and learning curve are some things to consider when choosing a framework.

  • What are some limitations of mock testing?

    Writing good mocks requires good understanding of dependencies. Otherwise, mocks may not accurately represent real-world behaviour. Mocking can lead to tight coupling between mocks and code under test.

    Overuse of mock objects as part of a suite of unit tests can result in a dramatic increase in the amount of maintenance that needs to be performed on the tests themselves.

Milestones

1999

Extreme Programming emphasizes unit testing and Test-Driven Development (TDD). Some adopters of Extreme Programming, based out of London, begin to think about how testing influences coding. They have been using "getters" to facilitate testing but they explore new ideas. They start avoiding "getters" and adopt composition, where test objects are passed via constructors. This is years before the term Dependency Injection is used for this design approach.

2000

Initial ideas of mock testing are presented at the XP2000 conference. At this time, the approach is called Endo-Testing. This name comes from the fact that mock objects are passed into domain code and tested from within. They claim that this simplifies testing architecture. It avoids polluting domain code since assertions are not in production code but in unit tests.

2001

EasyMock is released. It's the first library to provide dynamic mock objects.

Jun
2004

Version 1.0.0 of jMock is released. This provides an expressive API over DynaMock Java library. DynaMock itself comes from an earlier work by Nat Pryce who introduced mocking to Ruby. He emphasized assertions on messages passed between objects rather than just parameter values.

Jul
2008

Framework Mockito v1.5 for Java is released. By now, mock testing is more than just identifying where a test has failed. It's more about interactions among objects. Mockito simplifies mocking by taking a different approach compared to jMock or EasyMock. We don't have to set up expectations in mock objects in advance. We can simply create them and query them later after execution.

Apr
2007

Nat Pryce and Steve Freeman rework jMock to produce jMock2.

Dec
2008

Google releases Google Mock, a mocking framework for C++. Version 1.7.0 is released in 2013. In 2015, this is absorbed into the GoogleTest project.

Sample Code

  • // Source: http://www.softwaretestingmagazine.com/knowledge/unit-testing-fakes-mocks-and-stubs/
    // Accessed: 2019-03-03
     
    // When testing SecurityCentral, we use mocks to verify
    // that doors and windows are correctly instructed to close.
    public class SecurityCentralTest {
        Window windowMock = mock(Window.class);
        Door doorMock = mock(Door.class);
     
        @Test
        public void enabling_security_locks_windows_and_doors() {
            SecurityCentral securityCentral = new SecurityCentral(windowMock, doorMock);
            securityCentral.securityOn();
            verify(doorMock).close();
            verify(windowMock).close();
        }
    }
     

References

  1. Agostini, Dejan. 2017. "Unit Tests with Dependency Injection." Agostini.Tech, April 24. Accessed 2019-03-20.
  2. Berger, Hila. 2018. "Typemock vs. Google Mock: A Closer Look." Code Project, November 26. Accessed 2019-03-19.
  3. EasyMock GitHub. 2019. "easymock/easymock." February 15. Accessed 2019-03-20.
  4. Fowler, Martin. 2007. "Mocks Aren't Stubs." January 02. Accessed 2019-03-19.
  5. Freeman, Steve, Nat Pryce, Tim Mackinnon, and Joe Walnes. 2004. "Mock Roles, not Objects." Proceeding OOPSLA '04, ACM. Accessed 2019-03-20.
  6. Google Mock GitHub. 2015. "google/googlemock." August 26. Accessed 2019-03-20.
  7. JMock Library GitHub. 2019. "jmock-developers/jmock-library." February 02. Accessed 2019-03-20.
  8. Jenkov, Jakob. 2014. "Unit Testing with Dependency Injection Containers." May 24. Accessed 2019-03-20.
  9. Kapelonis, Kostis. 2016. "How to mock up your Unit Test environment." ZeroTurnaround, December 02. Accessed 2019-03-20.
  10. Lipski, Michal. 2017. "Test Doubles — Fakes, Mocks and Stubs." Pragmatists, on Medium, March 30. Accessed 2019-02-27.
  11. Mackinnon, Tim. 2009. "A Brief History of Mock Objects." Mock Objects, September 08. Accessed 2019-03-03.
  12. Mackinnon, Tim, Steve Freeman, and Philip Craig. 2001. "Endo-testing: unit testing with mock objects." Published in Extreme programming examined, pp. 287-301, Addison-Wesley Longman Publishing Co., Inc. Accessed 2019-03-20.
  13. Meszaros, Gerard. 2011. "Mock Object." xUnit Patterns, February 09. Accessed 2019-03-03.
  14. Mockito Wikis. 2012. "ReleaseNotes.wiki." Google Code Archive. Accessed 2019-03-20.
  15. Möller, Lovis. 2018. "Mock? What, When, How?." Blog, Codecentric, March 16. Accessed 2019-03-03.
  16. North, Dan. 2008. "The End of Endotesting?" Dan North & Associates, September 14. Accessed 2019-03-19.
  17. O'Neill, Antony. 2017. "How to write good tests." Mockito, on GitHub, May 09. Accessed 2019-03-03.
  18. Paralogarajah, Piraveena. 2017. "What is Mocking in Testing?" Medium, October 21. Accessed 2019-03-03.
  19. Plone Docs. 2019. "Mock Testing." Plone Docs, February 03. Accessed 2019-03-03.
  20. Santorossa, Marco. 2017. "Mock Dependencies: Instance and Configuration Injection With Swift." Medium, September 04. Accessed 2019-03-20.
  21. SoapUI. 2019. "API Mocking: Best Practices & Tips for Getting Started." SoapUI, SmartBear. Accessed 2019-03-03.
  22. Telerik. 2019. "Unit Testing for Software Craftsmanship." Telerik, Progress Software Corporation. Accessed 2019-03-19.
  23. Verma, Shivangi. 2017. "Unit Testing using xUnit." Blog, Systems Plus Group, October 05. Accessed 2019-03-20.
  24. Wikipedia. 2019. "Mock object." Wikipedia, February 26. Accessed 2019-03-03.

Further Reading

  1. Freeman, Steve, Nat Pryce, Tim Mackinnon, and Joe Walnes. 2004. "Mock Roles, not Objects." Proceeding OOPSLA '04, ACM. Accessed 2019-03-20.
  2. Agostini, Dejan. 2017. "Unit Tests with Dependency Injection." Agostini.Tech, April 24. Accessed 2019-03-20.
  3. Kapelonis, Kostis. 2016. "How to mock up your Unit Test environment." ZeroTurnaround, December 02. Accessed 2019-03-20.
  4. Mackinnon, Tim. 2009. "A Brief History of Mock Objects." Mock Objects, September 08. Accessed 2019-03-03.
  5. Fowler, Martin. 2007. "Mocks Aren't Stubs." January 02. Accessed 2019-03-19.
  6. Lipski, Michal. 2017. "Test Doubles — Fakes, Mocks and Stubs." Pragmatists, on Medium, March 30. Accessed 2019-02-27.

Article Stats

Author-wise Stats for Article Edits

Author
No. of Edits
No. of Chats
DevCoins
3
4
2587
11
1
2314
1465
Words
9
Likes
57K
Hits

Cite As

Devopedia. 2021. "Mock Testing." Version 14, June 28. Accessed 2023-11-12. https://devopedia.org/mock-testing
Contributed by
2 authors


Last updated on
2021-06-28 16:13:40