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 User
.
module.exports = new MockUser;
|
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.
'use strict';
|
Listing 2: Using a mock in Customer.js
Once the mock is in place in Customer.update()
, the Customer
code can now be tested as shown in Listing 3:
'use strict';
|
Listing 3: Mocking behavior in Customer allows the object to be tested
Mocking has been an important part of software testing for a long time. Design patterns for using mocks are well known. In fact, a whole industry has evolved around developing and using mocks. Most developers committed to unit testing use mocking frameworks since mocking can get quite complex very quickly. There is little sense in reinventing the wheel when a tried and true mock framework exists. Using a mock framework saves time and encourages developers to follow best practices. At mabl, we use mocking services for two different parts of our application. Mockito serves as the mocking tool we use when unit testing different parts of our application connecting to back end data components. Mockito is designed for Java applications and is a popular tool among Java developers. In addition, given our front end uses Javascript with Node and a React framework, we use Sinon for mocking. This link provides a comprehensive list of mocking frameworks available.
Get the CodeYou can find the source code that demonstrates how to make a developer defined mock on GitHub, here. |
Mocking Services
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.