The Problems of Test Driven Development
A common problem that developers committed to Test Driven Development (TDD) have is testing code that has dependencies which are under development or unavailable. This is where Mocks come in. For example, take a look at Figure 1 below. The
Customer object on the left side of the illustration depends upon functions found in the
User object on the right.
Figure 1: Well designed software encapsulates code according to areas of concerns
There is a problem. Work is at a standstill. The developers of the
User object cannot complete their work because they are waiting for the Data Team to finish working on the table and schema designs in the database. Thus, the
Customer developers are waiting on the
User developers and the
User developer are waiting on the Data Team. Clearly the situation is unacceptable. But, what’s to be done? The answer is to use mocks.
A mock is a temporary object or service that emulates behaviors that are expected to be delivered later on.
Using a mock object allows the developer to perform testing on his or her work, while other development is underway. In the case illustrated in Figure 1, previously, the developer can test the function,
Customer.update(user_data), despite the fact that an external dependency(s) might not be available. The developer simply mocks the dependency, in the case,
User. Listing 1 below shows a developer defined mock,
MockUser. As the name implies,
MockUser mocks the expected behavior in
Listing 1: A simple developer defined mock object in Node.JS
Listing 2 shows a way to implement mocking into an object that has external dependencies. In this case we’ll use a
MockUser directly within the
Customer object. The Node.JS code in Listing 2 checks to see if an environment
DEV_ENV exists and have been set to the value,
test. If so, the mock is used.
Listing 2: Using a mock in Customer.js
Once the mock is in place in
Customer code can now be tested as shown in Listing 3:
Listing 3: Mocking behavior in Customer allows the object to be tested
Get the Code
You can find the source code that demonstrates how to make a developer defined mock on GitHub, here.
In addition to using mocks to work with source code, you can also use mocks to emulate API behavior. For example, should your client side code have a dependency that makes GET requests to an API endpoint that is under development, you can use mock technology to emulate the request/response behavior of the API endpoint. For example, should you be developing an API using Java, you can use WireMock to mock your API. For .NET you can use mock4net and for Python there is, mock-server. The PHP community offers http-mock.
One of the better techniques for implementing mock services is to ensure that your development methodology supports the Specification First approach to API design. Using Specification First means that you design your API using one of the common API specifications, RAML, OpenAPI or API Blueprint. Then once the design is created using a specification, you can use community tools to automatically create simple mocks servers against that specification. You can use a tool such as SwaggerHub to auto-generate a mock web server using a specification written OpenAPI. SwaggerHub allows you to generate the server in a variety of languages. go-raml-mocker allows you create mock web servers against a specification written in RAML. For those shops creating specification under API Blueprint, there is api-blueprint-mockserver.
Putting It All Together
Mocking is a powerful technique that is used by many development shops dedicated to comprehensive testing in general, and Test Driven Development (TDD) in particular. Using mocks speed up development time while not sacrificing code quality. It takes a bit of time and attention to get comfortable using mocks. But, once the concept is understood and mocking techniques are mastered, developers, test engineers and testers will experience significant benefits. Mocking provides the power and flexibility to rapidly implement effective testing that is well suited for the Continuous Integration/Continuous Delivery pipeline. Adding mocks to your testing toolbox will improve both the value of the test you write and the quality of the code you make.