Service virtualization (SV) has evolved as a popular technique and technology over the last decade. Traditionally, SV has primarily been used by testers to simulate other application components that the application under test interacts with. Typically, virtual services have been created and maintained by center of excellence (COE) teams.
This meant that such efforts were often isolated from other personas, such as developers, test data engineers, deployment engineers, release engineers, and so on. For example, developers typically use programmatic techniques (such as mocking and stubbing) to support their unit and component testing efforts, and such assets are not re-useable by testers (and vice-versa). Similarly, test data engineers fail to leverage the synergies between virtual services and test data. In addition, deployment engineers fail to leverage virtual services to simplify and automate the provisioning and deployment of their environments.
With the increased adoption of DevOps, continuous integration (CI), continuous delivery (CD), and continuous testing (CT) practices, SV activities can’t continue to be performed in isolation, as they traditionally have been. It is imperative to integrate SV efforts with other activities in the CI/CD/CT/DevOps lifecycle to enable better collaboration and frictionless agility. This new approach to SV is what we call “continuous SV.”
This is the first of a two-part series of blog posts on continuous SV. In this blog, we will describe some best practices for establishing continuous SV as part of DevOps. In our second post, Continuous Service Virtualization, Part 2: Steps for Optimizing DevOps, we will discuss four key steps for leveraging continuous SV to optimize collaboration and flow in the DevOps lifecycle.
What is Continuous Service Virtualization?
“Continuous” SV is derived from the principle of “continuous everything” in DevOps. Continuous SV is a key component of CD within the DevOps framework. With this approach, SV activities are embedded across the different phases of the CI/CD lifecycle, as opposed to being employed in a single “testing phase.” SV activities are performed collaboratively by different personas, such as developers, API engineers, testers, deployment engineers, and so on. As assets are progressively built and maintained, they are shared by these different teams. (See figure 1 below.)
Figure 1: Continuous SV concept
Key Practices for Continuous SV
The following are the key practices that enable continuous SV.
Shift-Left SV Definition Activities
As with most activities in the CI/CD lifecycle, continuous SV also requires that most of the SV work (such as specification of virtual services, and virtual service generation, updates, and maintenance) “shifts left,” so it happens mostly during the CI part of the DevOps lifecycle. This minimizes the delay that SV processes can cause during the CD part of the lifecycle, helping to speed deployment cycle time. (See figure 2 below.) We will describe what SV activities happen in each stage of the lifecycle later in this blog.
Figure 2: Continuous SV along the CI/CD pipeline
Adhere to the Test Pyramid: Use Progressive Virtualization
The test pyramid is one of the key tenets of shifting testing left. This means that more and more SV processes need to support tests in the lower half of the pyramid, for example unit, component, integration, and component tests. (See figure 3 below.)
Figure 3: Mapping types of virtual services into the test pyramid
This also influences the type of SV approach we use:
- For the vast majority of unit and component tests, which are typically run by developers, we need to use lightweight, synthetic virtual services (aka mock services). Such virtual services are created synthetically (as opposed to recording a real service) using various techniques, such as by defining request-response (RR) pairs for an API, for example. This is important in the development phase, as the dependent service may not yet exist in order to be recorded. However, developers can easily create a mock service for the dependency based on its API specification. Mock services may be augmented using synthetic test data to provide support for a wider range of behaviors in the virtual service. See more on the interplay between virtual services and test data management in the following section.
- For the vast majority of tests in the middle tiers of the pyramid, such as integration, contract, and system tests, we recommend hybrid virtual services. Hybrid virtual services are a mix of synthetic and recorded virtual services (when dependent services already exist). These virtual services would be complemented by hybrid test data, which is a mix of synthetic and more realistic test data, which is created by taking a subset of data from production and masking it. Typically, these tests (as shown in Figure 2) are run in the CD part of the DevOps lifecycle. This means that such services must be created ahead of time and provisioned and deployed into the appropriate test environment, along with the application binaries and other test assets, such as test scripts and test data.
- For most end-to-end, business process, and user acceptance tests, we need to provide more realistic virtual services that are created from service recordings. This is practical since we expect most endpoints to exist by this phase of the lifecycle. Such services will be complemented by realistic test data that is most commonly obtained from production environments.
Note that the test pyramid applies not just to functional tests, but performance tests as well. The reason we point this out is that virtual services play a key role in performance testing at all levels. It does so by emulating not just the functionality of the endpoint, but also the performance of the dependent endpoint, so that the performance of the target application can be tested completely.
Use Progressive Virtualization
To map the needs of virtual services to the test pyramid, we need to use “progressive virtualization” (see figure 4 below). Progressive virtualization means that we first build simple lightweight synthetic virtual services (which are the easiest to create) for the development/unit test part of the CI/CD lifecycle. As we move from left to right along the lifecycle, our virtual services progressively become more realistic to support the latter stage tests—using more robust test data scenarios and/or using recorded virtualization for services that have been implemented by that stage.
Figure 4: Progressive virtualization
This is different than the traditional mocks and stubs that developers create for unit testing. These traditional elements are often not re-used by testers (for latter stage tests) or by other developers. On the other hand, in the case of progressive virtualization, the same lightweight virtual services are progressively (or continuously) enhanced, re-used, and shared with multiple teams, which improves the productivity of all teams.
Use a Virtual Service Catalog and Gateway
Re-use of virtual services in progressive virtualization, as described above, is supported by the use of an integrated service catalog and gateway (See figure 5 below). An SV catalog provides a centralized repository for sharing and managing virtual services across teams and applications. In addition, using a gateway allows parameterized access from clients to different versions of the virtual service (or a real service if available, for example in pre-production testing) without changing the client code.
Figure 5: Continuous SV with Service Catalog
Use Service Virtualization in Conjunction with TDM
Continuous test data management is a key practice for enabling CT. When complemented with test data, virtual services enable tests to be more robust in their ability to support a greater range of scenarios and interactions with the simulated endpoint.
In fact, the type of test data used (whether synthetic, hybrid, or production-like) correlates with the extent of service virtualization used. At the bottom of the test pyramid, we aggressively use both synthetic test data and virtual services. Towards the top of the pyramid, we use more realistic test data with real application components. We can use hybrid approaches for the middle tiers.
When using virtual services for test data, we need to make sure that we maintain consistency between data used to drive the tests, the application database, and the virtual service. The first two are typically taken care of by test data management (TDM) tools. For the virtual service, we need to either record or synthesize the virtual service with the same data set used for the test. (See figure 6 below.)
Figure 6: Synchronizing test data with virtual services
Integrate SV with CI/CD Processes
In order to achieve continuous SV, we need to ensure that the provisioning and deployment of virtual services are also automated along the CI/CD lifecycle. As discussed in the previous section, this is especially important in the CD part of the lifecycle, where we need to minimize elapsed time to reduce cycle time. This can be achieved by integrating the deployment of virtual services with deployment automation tools. For applications that are deployed in containers, we may package test assets (including virtual services) in side-car deployment containers and deploy them alongside application containers.
In this blog we have discussed what continuous SV is and its key practices. In the following blog, Continuous Service Virtualization, Part 2: Steps for Optimizing DevOps, we will discuss the continuous SV lifecycle and how it helps to optimize DevOps.