A short tutorial of the Ekko Proxy Service Virtualization tool
Before I start on the tutorial and share my experience with Ekko Proxy, let me start off with some basics about Service Virtualization — if you know all this then I suppose you can skip this section.
What is Service Virtualization and how does it differ from Stubs and Mocks
There are many resources on this but here is my quick take on it; Service Virtualization is the process of setting up virtual copies in place of real services or services being developed. Virtualized services or APIs are always called remotely, just like you would with the real service, and are often created from recording existing services or generated from API definitions like OpenAPI / Swagger or WSDL. So how is this different than stubs or mocks you may ask; well firstly stubbing and mocking are almost always done exclusively in-process working directly with classes, methods and functions. Secondly they are also most often handcrafted, use hardcoded test data, are very context specific and live together with the application project that they are used for, meaning they are not readily shareable. Virtualized services on the other hand, once created, can exist as part of an enterprise wide environment with services used and maintained by multiple projects / teams — thus making them highly shareable saving you valuable time and effort. Personally I don’t think stubs have much of a place in a modern development environment, as they frequently become a maintenance nightmare, whereas mocks are excellent for mocking dependencies in unit tests.
What about stub or mock servers? I would say that these are in principle service virtualization tools (as they are called remotely), though some would argue that to qualify as proper service virtualization tools they should have features like: support for more than one protocol, have a user interface for ease of use and less tech-savvy users, recording capability, and the ability to simulate non-functional characteristics such as response times or slow connections and so forth. The tool I’m reviewing, Ekko Proxy, does have these capabilities but it’s not one of the big players in the field. In terms of features I’d say that it probably fits in mid-level, though that’s not a bad thing given it provides what you need most of the time and for a much cheaper price point than the bigger players.
The big players in this field come from the likes of CA / Broadcom, SmartBear, IBM, Parasoft, Traffic Parrot etc. and they all have comprehensive enterprise tools in this space handling a multitude of different protocols like HTTP, MQ, TCP, JMS, RMI, databases etc. where a small player like Ekko Proxy only currently supports HTTP and JDBC. Nine times out of ten though I bet HTTP is the protocol you want in order virtualize your REST / SOAP based services. Further the caveat of the big players is that they are prohibitively expensive for many companies and due to their comprehensiveness they usually have a steep learning curve that will likely require training and / or their consultants to help you. At the other end of the scale there are lots of free / open source options, however what I find with these are that they are often not easy to use and require lots of setup / scripting or even coding, and once running are a bit like a black box i.e. you have little to no visibility of what’s going on. Others offer online mock servers e.g. Postman, MockLab etc. but I’d personally be quite wary of using these especially if working with sensitive test data. Lots of companies use production like data (or even raw production data!) when testing, and even if anonymized it’s not something you would want to send to some online service that you have no control over.
Lastly if you find yourself searching for service virtualization tools online and find these comparison sites that pops up on the first few pages then just be a little cautious of the objectivity of these by remembering that companies frequently pay to be listed on them making it harder for the smaller players to be fairly represented.
Using the Ekko Proxy Service Virtualization tool
To demonstrate usage of the Ekko Proxy tool I’ve chosen to use a Material-UI template project from Minimal (v1.2.0) as a UI making backend REST calls, some of which I will virtualize — note from hereon when I refer to mocks I mean virtualized service mocks. Material-UI is one of the best, if not the best, ReactJS frameworks out there in my view and the Ekko Proxy UI happens to be built on this great framework.
OK let’s get started then!
My Setup
My setup simply consists of Java 8 (any version above this will work too) and the Ekko Proxy v1.5 jar downloaded from the website www.ekkoproxy.com. Running “java -jar ekkoproxy-1.5.jar” on a command line starts up the proxy and putting in http://localhost:4040 in my browser’s (Chrome in my case) address bar loads up the Ekko Proxy UI as seen here:
For the demonstration UI I have the latest Node.js installed and the Minimal Material-UI ReactJS project which I have initialized with the command “npm install”, to install the node module dependencies, and then run in development mode using the “npm run start” command. The latter will open a browser window with the address of http://localhost:3000 showing the Minimal sample UI:
Getting started
The Minimal project uses the popular axios module to make REST calls but as it doesn’t come with a back-end to handle REST calls it uses the axios-mock-adapter module to mock the calls from the UI. This works well for the purpose of the Minimal project in that you can download it and run it without requiring any other downstream dependencies. That said however it has all the downsides of being a non-virtualized mocking tool, as described in the What is Service Virtualization… section, and as such should be confined to unit testing with a combination of say Jest and Enzyme as an example in a React JS based environment. When running the Minimal project out of the box you also notice another downside to this kind of mocking which is the lack of REST calls in the developer network tab i.e. as you navigate through the UI you have no idea of what calls are being made and when they are made etc.
For demonstration purposes I will only pick a few of the axios mocked APIs to virtualize and before making any code changes I need to deal with Cross-Origin Resource Sharing (CORS) — yes that often annoying browser feature that blocks XHR i.e. AJAX calls. As the UI is running on port 3000 and I will setup the virtualized services on port 3001 the browser will send a CORS pre-flight request with a HTTP method of OPTIONS to seek approval from the server to make the actual call. Given the server in my case is Ekko Proxy I will simply define an ‘approval’ response to any pre-flight request in the Ekko Proxy Mock Editor as per below.
This will respond with all the Access-Control-* headers allowing any HTTP header, method and origin for any URL. It goes without saying that actual services should always deal appropriately with CORS.
The Demo
For demoing I’ve picked the Minimal UI user profile page and the blog post part as highlighted in the screenshot below:
To get to this page there are a few APIs called and the way (ignoring login); GET /api/account/my-account, GET /api/user/profile and GET /api/user/posts which are currently mocked using the axios-mock-adapter module. The Post button has no implementation so I’ll add a call to a new POST /api/user/posts API which will demonstrate the use of mock scenarios. Scenarios basically allow a state to be assigned and changed as a matching mock is run. It’s essentially a state machine with an initial required state of “Started” and a new state value once invoked. This allows multiple mocks to be defined for a scenario that will return different responses as the state value changes — even for the same resource. This will work nicely for mocking new posts being added to the list of posts with the GET /api/user/posts mock returning different posts depending on the current scenario state. Anyway lets add all the required mocks in Ekko Proxy. Note for all the mocks I’m adding the same response headers which are:
- Content-Type: application/json
- Access-Control-Allow-Origin: *
Now for the my-account and profile mocks which I define as:
GET /api/account/my-account
GET /api/user/profile
This only takes me a few minutes to add so now it’s time for the scenario mocks. For these I will add a combination of GET and POST methods to the user posts API (/api/user/posts). The GETs will retrieve different responses depending on the current scenario state and the POSTs will be used to move the scenario from one state to another based on the posted message from the UI.
GET /api/user/posts — Started
So with the scenario name of ‘User posts’ and the special ‘Started’ required scenario state this mock will be the one that provides the initial user posts data until a POST is invoked to move the state on to something different than ‘Started’ — and that mock I define next.
POST /api/user/posts — Started -> New post added
This POST request mock to /api/user/posts will match if the request body contains the words “New post using scenarios!” and then change the scenario state from ‘Started’ to ‘New post added’. This means I now have to define a mock to GET /api/user/posts which will return the user posts for this new scenario state.
GET /api/user/posts — New posts added
The mock above returns an additional user post in the JSON response. You could continue this way until you have covered all the scenarios you want and add much more complex matching logic too. I’ll define just one more mock that will allow me to return the scenario state back to ‘Started’ allowing me to run through the whole flow again.
POST /api/user/posts — New posts added
This last mock matches on the request body containing the word “reset” and moves the scenario state from ‘New post added’ back to ‘Started’ which means when the GET /api/user/posts API is called we get the starting users posts back and can start over with the testing.
With the all the virtual service mocks now defined it’s time to start up a new proxy so we are ready for the UI integration. Clicking ‘Create Proxy’ left hand navigation link takes me to the proxy setup page which I fill in as per below.
This is like a bare minimum setup where I’m setting up the new proxy on localhost port 3001 with a target of localhost port 3000 which is where the UI is running. Normally this should be the target of your downstream system but for this demo I don’t have any — it doesn’t really matter what I use here as the plan is to handle all the requests I send to the proxy in playback mode. Likewise I’ve left the recording settings empty as I’ll be handling the requests using the mock feature only. The only thing to do next is to hit the ‘Create HTTP Proxy’ button and voila!, we are now have a proxy running on port 3001 and are ready for UI integration. It should be noted that when making changes to the mocks after starting a proxy then the proxy needs to be stopped and started again to pick up the changes.
UI Integration
The Minimal UI project is currently using the AxiosMockAdapter module to stub out calls so I start by modifying the AxiosMockAdapter configuration (utils/mock.js) to allow calls to passthrough if there are no matching mock. This is done by adding the line in italics:
const axiosMockAdapter = new AxiosMockAdapter(axios, {
delayResponse: 0,
onNoMatch: 'passthrough'
});
Next I go to the redux/slices folder and change the endpoints in authJwt.js and user.js to those of the APIs I have virtualized i.e. prefixing the URLs with http://localhost:3001 e.g.:
const response = await axios.get(
'http://localhost:3001/api/user/profile'
);const response = await axios.get(
'http://localhost:3001/api/user/profile'
);
Note that in proper project it would be best practice to use environment variables for non-relative endpoints.
In the user.js I add a new reducer method for the new post message success which simply sets loading to false as there is no response payload:
Then I add a new function to make the call to post a new message:
export function onPostMessage(message) { return async (dispatch) => { dispatch(slice.actions.startLoading()); try { const response = await axios.post( 'http://localhost:3001/api/user/posts', message ); dispatch(slice.actions.postMessageSuccess(response.data)); } catch (error) { dispatch(slice.actions.hasError(error)); } };}
Next I need to hook up this with the Post button on the user profile page located in the views/user/ProfileView/Profile folder. I start with the PostInput.js and add a few handlers:
const { user } = useAuth();const [message, setMessage] = useState('');const handleChangeMessage = (event) => { setMessage(event.target.value);};const handleKeyUp = (event) => { if (event.key === 'Enter' || event.keyCode === 13) { handlePost(); }};const handlePost = () => { if (!message) { return; } if (onPost) { onPost({ messageId: faker.random.uuid(), message: message, contentType: 'text', attachments: [], createdAt: new Date(), senderId: user.id }); } setMessage('');};
Then I add them to the TextField component:
value={message}onKeyUp={handleKeyUp}onChange={handleChangeMessage}
, and to the Button component:
onClick={handlePost}
The onPost is a new function which is passed into the PostInput component so I also add it to the PropTypes. Lastly in the parent Profile component (index.js) I define the onPost handler as below:
const dispatch = useDispatch();
const handlePostMessage = async (value) => {
try {
Promise.resolve(dispatch(onPostMessage(value))).then(() =>
dispatch(getPosts())
);
} catch (error) {
console.error(error);
}
};
Note the use of Promise here to ensure the getPosts() action is executed after the onPostMessage action. This will ensure we display the up to date list of posts. Finally I add the handlePostMessage function to the PostInput component:
onPost={handlePostMessage}
That’s everything connected so its now time to try it out!
Now when loading the Minimal app in the browser we should see the my-account request in the network tab and also in Ekko Proxy.
In Ekko Proxy we can see the CORS OPTIONS request being handled by our CORS mock first followed by the my-account request itself. Then when clicking on the user profile in the UI I should get another two requests (user profile and posts) or four if counting the CORS ones as seen below:
So far so good — all the requests where handled by the proxy as defined in the mock editor. So now let’s try posting a message to test the scenario handling. To do this I post the starting scenario trigger message:
Clicking the Post button triggers the new POST /api/user/posts call which changes the scenario state for the “User posts” scenario meaning that the other GET /api/user/posts mock with matching scenario state is now the one responding. We can see that as the new post message appears on top of the older post:
Likewise in Ekko Proxy we can see the posted message and the subsequent get posts request with the new post in its response.
Finally when I post the “reset” message I get back to the starting post messages which is perfect. Note if posting anything else then because there are no matching mock or recording, the message is sent to the target which I pointed at the UI. The UI in turn returns a 404 (No Found) without a CORS header which causes an error which is logged to the console and blocked — that is to be expected though given we have no actual server to handle those.
Setting up the mocks was pretty easy and really took me no time at all so I can see definitely see the benefits of this tool. And if you are working for a corporation that has multiple teams and backend systems and you build up a shareable library of mocks / recordings for the systems then this is where you can really start to reap the benefits of using service virtualization tools like Ekko Proxy.
Other Features
There are plenty of other features to Ekko Proxy that I have not covered here like recordings, JDBC mocks and the various other tools that are embedded in it. The tools are all pretty useful in their own way but the most useful of them are probably the JWT, WSDL and OPEN API tools. The latter two allows you to generate mocks directly from WDSL or Open API documents which can really help accelerate mock creation. The generated mocks can be used straight away but will almost certainly need some modifications to the response for example to make it useful in a test. The below screenshot shows a generated response for a SOAP binding operation defined in a WSDL:
Clicking on a binding or operation gives you an option to generate mock(s). Likewise an Open API or Swagger document (JSON or YAML format) can be used in the Open API tool:
Clicking on a group or resource level gives you an option to generate mock(s).
That concludes the tutorial and I hope you will find this tool as useful as I have — definitely one I’ll add to my toolkit going forward.