4 Interaction testing using mock objects

 

This chapter covers

  • Defining interaction testing
  • Reasons to use mock objects
  • Injecting and using mocks
  • Dealing with complicated interfaces
  • Partial mocks

In the previous chapter, we solved the problem of testing code that depends on other objects to run correctly. We used stubs to make sure that the code under test received all the inputs it needed so that we could test the unit of work in isolation.

So far, you’ve only written tests that work against the first two of the three types of exit points a unit of work can have: returning a value and changing the state of the system (you can read more about these types in chapter 1). In this chapter, we’ll look at how you can test the third type of exit point—a call to a third-party function, module, or object. This is important, because often we’ll have code that depends on things we can’t control. Knowing how to check that type of code is an important skill in the world of unit testing. Basically, we’ll find ways to prove that our unit of work ends up calling a function that we don’t control and identify what values were sent as arguments.

The approaches we’ve looked at so far won’t do here, because third-party functions usually don’t have specialized APIs that allow us to check if they were called correctly. Instead, they internalize their operations for clarity and maintainability. So, how can you test that your unit of work interacts with third-party functions correctly? You use mocks.

4.1 Interaction testing, mocks, and stubs

4.2 Depending on a logger

4.3 Standard style: Introduce parameter refactoring

4.4 The importance of differentiating between mocks and stubs

4.5 Modular-style mocks

4.5.1 Example of production code

4.5.2 Refactoring the production code in a modular injection style

4.5.3 A test example with modular-style injection

4.6 Mocks in a functional style

4.6.1 Working with a currying style

4.6.2 Working with higher-order functions and not currying

4.9 Partial mocks

sitemap