Services may be unavailable for a number or reasons, for instance that a module is still in the development phase, or a that third-party service is too expensive to make available to QA in early tests. Other times test environments may be available, but the test data is constantly corrupted, so the tests don't create any actual value. You probably have heard the phrase "the application usually behaves like this in the test environment, but it should work when we get the artifact to production" a million times.
In this article, we will cover the key concepts of Service Virtualization; what it is, how it works and what it can do for you.
Key Concepts of Service Virtualization
In short - it's an intelligent simulation of a service. It's an API, or some other form of end-point, which acts in accordance with the rules of some sort of contract. The virtualized service is aware of parameters and data-types, and knows which requests are valid, and which aren't - and responds accordingly. So when you request the simulated service, you get a response which is valid according to the specified contract, just as if it would have been a non-simulated service.
Well, there are several reasons for this. But as stated earlier, it's all about breaking constraints, no matter if they are technological or financial. Common problems which can be resolved by simulating service include:
- Test Environments - How much time do developers and QA spend just waiting for access to the test system? And when Dev get their turn, QA has to wait - and the other way around. It is usually the Operations department which is responsible for deploying the correct artifacts and loading the proper test data, and when they are occupied with important production issues instead - everyone has to wait for the test environment to become available or restored.
- Test Data Management - The data set in test environments is easily corrupted. A single test case which fails to restore the test data once it's completed will cause errors relating to duplicate data the next time it's executed. And again, there is usually a dependency on the Ops team to take the time to restore a corrupt test environment.
- Identify Issues early in the SDLC - Software issues should be found as early as possible in the Software Development Life-Cycle (SDLC), as mitigation costs increase rapidly the later you discover them. If you can give developers and QAs access to systems which usually are not available until integration testing, or even the production system, how many more issues can you then find earlier in the SDLC?
- Integration Costs - External providers may charge not only for using their production system, but also for the UAT/Sandbox environment. Even if the per-transaction fee may be low, it can add up to quite a cost if you want to run a load test on your system.
- The Problem with Mocks - The issues relating to mocked services, or "stubs", are covered in the next section. Mocking a service may seem like a easy way to validate integrations, but there are some problems associated to it.
To mock a service means to develop a stand-in, or stub, for the service. When you request the mock, it will respond with some sort of data. This sounds similar to a virtualized service, so why not go for the mock instead? Well, virtualizing the service actually has some key benefits:
- Automatic Creation - A mock needs to be programmed by a developer, whereas a simulation can be created by anyone.
- Rely on the Simulation - A mock needs to be maintained by the developer as well. Running tests against a mock integration which is not up-to-date with the live integration, may cause false-positives in testing, which will not be detected until the artifact has reached production. With simulations, changes in the integration can be updated by anyone - or even automatically.
- Let Developers Develop - Software Developers should be doing what they do best - transforming business requirements into software solutions. Writing and maintaining mock integrations will consume valuable resources, and lower over-all output.
- Rich Test Data - Mocks are usually quite stupid. They may respond with "everything is OK!" no matter what data you provide to them, which is useless for negative test cases. It's not uncommon that a mocked service responds with the same data, no matter which data you request it with - making request/response and parameter validation almost impossible.
- Test for Performance - Also, mocks are usually too good at what they do! They respond almost immediately, since there isn't any processing of business data going on in the background. So how do you know how your application behaves when the service you are integrating towards, isn't behaving perfectly?
As a concept, Service Virtualization is not bound to any specific set of services. All communication which is based on Requests and Responses, and carried over the standard internet protocols TCP or UDP can be simulated.
It's common to simulate Web Services wrapped in HTTP, such as SOAP and REST, but other Internet protocols such as SMTP, IMAP or SNMP works just as well. This means that you can simulate anything from a Web API to a Mail Server or even the performance reports from a Network Router. Is your SMS Provider charging you for sending text messages in their sandbox environment? Then you can set up a simulation of their SMPP-based end-point instead! You can create simulations of media protocols as well, such as RTP, to create a virtualized voice or video service.
Proprietary protocols works just as well. If you have a business solution from SAP or Oracle, or maybe an internal legacy business system, you can simulate those integrations too. Actually, legacy systems are usually very beneficial to simulate, as their test environments often are limited, or completely unavailable.
Furthermore, the concept is not bound to external modules, you can simulate an internal Java component, or even a SQL database. Any sort of constraint, and any sort of unavailable dependency, can and should be simulated!
You can create a simulation in many different ways, but the most common ones are:
- Using an API Specification - This is very useful when simulating Web Services where WSDL or XSD files may be available to describe the rules of the communication.
- Using Live Data - If you haven't got an API Specification, you can provide the simulation with sample data from a test or live system. The system will listen in on the requests and responses in the communication, and start building a set of known functions, and their associated parameters.
- Using R/R Data - If you for some reason can't listen in on the communication, you can feed the simulation from known Request & Response Pairs. These data pairs can usually be extracted from a test environment, or from the logs of a live system.
- Manually - Of course you can create the simulation data from scratch, but this is usually very time-consuming.
It's important to remember that a simulation is not a database. So when you add a data record using a virtualized API, the record will not be available to retrieve from the virtualized API later on, as the simulated service will not keep it.
But is this really an issue? When you perform testing of a module, you are usually not interested in if some external service could add a record to its internal database or not. Instead, you want to verify that your module-under-test can integrate properly towards the service. And this is exactly what a simulated service can provide for you!