Mocking with Mountebanks is great until you have a scenario that just does not work. Everything seems right, but mountebank never matches the request with the mock you created. The Mountebank logs show the ominous message 'no predicate match, using default response'.
For an introduction to API tests with mountebank / typescript check my post https://angela-evans.com/easy-api-tests-with-mountebank/
API connects Directly to Imposter
The standard setup for an API is to point directly to a mock service. Mountebank will inspect all incoming requests and try to match it’s properties (method, path, body, …) to predicates in the imposter. If no match exists, then mountebank returns a default response.
The question of ‘Why does my predicate not work?’ can take hours to solve if you do cannot debug the API you are testing. The request matching is a black box and mountebank logs offer no insights.
Record Traffic with a Proxy
However, there is an easy way to ‘debug’ the traffic between the API we are testing and the mountebank imposter: Proxies!
A proxy imposter forwards all traffic unconditionally to another URL / port and records requests and responses.
After running the failing test, we can inspect the traffic between API and the imposter which does not work.
The Typescript / Node package @anev/ts-mountebank makes it easy to create a debug proxies. The snippet below will create a proxy on port 5000 with the following behavior:
- Forward all requests to http://localhost:5001
Sample: http://localhost:5000/GetBooks => http://localhost:5001/GetBooks - Record requests and responses
let proxyImposter = new Imposter().withPort(5000)
.withStub(new Stub()
.withProxy(new DebugProxy(`http://localhost:5001`)
.withMode(ProxyMode.ProxyAlways);
await new Mountebank().createImposter(proxyImposter);
Recorded Stubs
After pointing the API to the proxy imposter and running the test, the generated stubs are available in the mountebank admin console. On localhost the URL is http://localhost:2525/imposters/5000. The output will contain information on predicates and responses.
Predicates are the conditions mountebank uses to match requests to imposters, and should mach the predicates on the mocks created by your tests. For each different set of predicates, the proxy creates a new ‘stub’. The stub contains a set of predicates and all responses fore requests matching these.
- Not all available predicates need to be set to match imposters, for instance GET requests do not have a body. For paths etc. it can be easier to set the comparison only compare the start/end of the path.
- In ‘proxyAll’ mode all the responses which match the predicates of the stub are in the response array.
Note: When tests are always run through a proxy imposter, it helps to re-create the proxy regularly to prevent it from growing too big. This means the proxy only contains a small amount of traffic, which makes it easier to find relevant information.
Conclusion
Mountebank proxies are a useful tool to analyze problems whith mountebank imposters. For this reason it is helpful to route the traffic through a proxy during development. This means most problems with request matching are easily solved without re-configuring the API or debugging it.