skip to content

What is service virtualization, and when do you test against a virtual service instead of the real dependency?

level: juniorimportance: must knowfreq 62%

answer

  1. Someone else's service, not your object
  2. The swap happens at the network boundary
  3. Same protocol and address, different process
  4. Rules you wrote, or traffic you recorded
  5. Control and speed bought with fidelity

basics

~20 s

Service virtualization replaces a dependency you do not control with a programmable stand-in that answers over the same protocol and address. Reach for it when the real service is unavailable, costly, rate-limited, or cannot be pushed into the state a test needs.

solid answer

~50 s

A virtual service is a separate process standing where the real dependency stands: the application opens the same kind of connection, speaks the same protocol and parses a real response off the wire, but the answer comes from rules you wrote or from traffic you recorded and replayed. The substitution happens at the network boundary, so no application wiring changes - only the address the client resolves. You reach for it when the real dependency is out of your control: a third-party sandbox that is offline overnight or rate-limited, a call with real-world side effects, a response you cannot provoke on demand such as a duplicate-submission rejection, or simply a suite that must run in minutes rather than hours. The price is fidelity: the stand-in is only as truthful as the day it was written, so it is paired with a small number of checks against the real thing.

code

pseudocode · 8 lines
pseudocode
// production configuration
filing_gateway.base_address = "https://gateway.revenue.example"

// test configuration - nothing in the wizard's code changes
filing_gateway.base_address = virtual_service.address()

virtual_service.when(method = "POST", path = "/returns")
               .respond(status = 202, body = { "receiptId": "R-84417" })

go deeper

for a junior

Be ready to say in one sentence that the stand-in is a separate process answering over the network, and to give two concrete reasons you would not call the real service - unavailable, or unable to produce the error you need.

for a middle

An interviewer expects you to explain both authoring styles, programmed rules and recorded-then-replayed traffic, and to say which parts of your own stack still run when a stand-in is in place: the client library, serialization, timeout and retry code.

for a senior

Show that you treat a stand-in as borrowed confidence. Name the decay, describe the small live tier you keep to re-earn it, and be able to tell a story where a stale stand-in let a real defect through.

for a principal

Own the policy: which dependencies get virtualized at all, who maintains each stand-in, how far the practice may spread before the suite is testing a fiction, and what the organisation buys by asking providers for a maintained sandbox instead.

## What the technique actually is Service virtualization means putting a programmable stand-in process where a real dependency would sit, and pointing the system under test at it. The defining property is *where* the substitution happens: at the network boundary. The application still opens a connection, still negotiates the protocol, still receives bytes it has to deserialize, still applies its own timeout, retry and error-mapping code. Only the identity of the process on the other end has changed. That is what separates it from replacing a collaborator inside the test process, which is a different technique with a different owner - there, the client library and everything below it never runs at all. A virtual service is defined in one of two ways, and a mature setup uses both: - **Programmed.** You declare rules: a request shaped like *this* returns a response shaped like *that*, with this status, these headers and this body. The rules are code or configuration you own and review. - **Recorded and replayed.** You route real traffic through a recording proxy against the real dependency once, capture the exchanges, then serve them back on later runs. Recording gives you shapes nobody would have invented - the odd header casing, the envelope field that is always present but never documented. Programming gives you the states the real service will not produce on demand. ## A worked example A tax-filing wizard walks a taxpayer through a return and submits it to a national filing gateway. The gateway's test sandbox is available 06:00 to 22:00, throttles a single client to a dozen submissions a minute, and issues credentials that expire monthly. The wizard's regression pack is 340 cases, and roughly a third of them touch submission in some way. Against the real sandbox that pack cannot run on a pull request: it is too slow, it fails outside working hours, and several of its most valuable cases - *the return was already filed for this taxpayer*, *the gateway rejected a field the wizard thought was optional* - describe states nobody can conjure on request. Against a virtual service the whole pack runs in minutes, at any hour, on every machine, and each of those states is one rule away. ## The five reasons teams reach for it 1. **Availability.** The dependency is down, shared with other teams, or only reachable from one network. 2. **Side effects and cost.** Real calls file real documents, charge real money, or send real messages. 3. **Determinism.** The real service returns yesterday's exchange rate, a rotating identifier, or a queue position. A test that asserts on any of those is a test that fails on Tuesdays. 4. **Unreachable states.** Error paths, throttling, partial outages and legacy responses that appear once a quarter are the paths most likely to be broken, and the hardest to trigger honestly. 5. **Speed and parallelism.** A stand-in has no rate limit and no shared account, so the pack can fan out across workers. ## What it costs Fidelity, and fidelity decays. A stand-in is a snapshot of a belief about another team's service, and the other team did not agree to freeze. The failure this leaf exists for is the quiet one: the filing gateway moved a monetary field from an integer in minor units to a decimal string, the stand-in kept returning the old shape, the wizard's parser truncated the value without raising anything, and a silent data corruption reached returns that had all passed 340 green cases. Everything about that run looked healthy. Nothing about it was evidence. So a virtual service is never the whole strategy. It carries the bulk of the cases - the parsing, the retry behaviour, the error mapping, the user-facing messages - and a deliberately small number of checks still run against the real dependency to keep the belief honest. Detecting the decay is its own discipline. ## Where it sits The technique is most useful one level above the smallest tests: component or integration tests, where you want the real client library, the real serialization and the real timeout configuration exercised, but not the real counterparty. It is not a substitute for exercising your own code, and it does not tell you whether the dependency works - only how your side behaves given a particular answer. ## The judgement an interviewer is listening for A strong answer names the boundary (out of process, over the protocol), names both authoring styles (programmed and recorded), gives a concrete reason the real thing was unusable rather than the generic 'it is faster', and volunteers the cost - that confidence from a stand-in is borrowed, and has to be re-earned on a schedule.

  • If the application code is untouched, how does the request actually reach the stand-in?
    Through configuration outside the code: the base address the client resolves is set to the stand-in for that run, or the environment routes the real hostname to it through a host mapping or a proxy. Address-level redirection is the safer of the two, because a test that has to rewrite hostnames tends to diverge from the production path in ways nobody notices.
  • When would you keep calling the real sandbox rather than stand it in?
    For the handful of checks whose whole purpose is to confirm the real counterparty still behaves as believed: authentication and handshake, the shape of a successful response, and one or two representative errors. Those run on a schedule rather than on every change, and they are what keeps the stand-in honest. Discovery work - learning undocumented behaviour before you can encode it - also belongs against the real thing.
  • Your stand-in returns a response the real gateway has never produced. Is that ever legitimate?
    Only as a deliberate, labelled hostile case: a truncated body or an unknown status to prove the client degrades safely. It is not legitimate as an ordinary case, because the test then documents behaviour that cannot happen and the assertion locks in a fiction. Keep invented responses in a clearly named group so nobody later mistakes them for recorded truth.

It is a film-set storefront. From the actor's side there is a door, a window and a sign, and they walk up to it exactly as they would to a real shop - but there is nothing behind the facade except what someone deliberately built, and the real high street keeps changing while the set does not.

saying these in an interview costs you the question

  • Treats it as identical to replacing an object inside the test process
  • Says a stand-in removes any need to touch the real dependency
  • Cannot name a single reason beyond 'the real one is slow'
  • Assumes recorded traffic never needs scrubbing or refreshing
  • Claims fidelity does not matter as long as the suite is green

context