Google Analytics

Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Friday, July 14, 2017

Introducing Mountebank!

I want to preface this next post with a bit of a disclaimer: The technical posts I primarily make tend to come from the point of view of someone with two thumbs (this guy) who is exploring some piece of technology new to him. I do it primarily for my own benefit. Having to create a blog post forces me to approach the subject in an organized manner rather than just going off and willy-nilly experimenting to no purpose. Secondly, I can document my own process as much for me to go back and diagnose issues I run into (see my last post) as it is to pass along that documentation to others I am working with. Finally, usually whenever I Google some troublesome issue no matter hwo obscure I think it might be, there are a couple developers out there that have run into the same or similar issue, and blog posts of others working through those issues have saved me a lot of time, if not my hairline. I feel like, no matter how small, maybe if I share, some other developer might find some little nugget that will help them get through some similar issue.

So if you're already an expert with mountebank and are looking for some new insight, you aren't going to find it here. Instead, I really hope you read through this series of posts and add your own insights or corrections, for there are sure to be some.

With that let me introduce (*some old-timey fanfare plays on a nickelodeon*) mountebank! Mountebank is an old-timey word for imposter or charlatan, a snake-oil salesman. In this context mountebank (I use MB for short here) is an open-source tool for impersonating related services in software testing. Automated testing of downstream service calls can, frankly, be a bitch. Yes, you can work out some mock, but service calls are way more unpredictable than a simple mock. What if the service or port is unavailable? What is the service returns some garbage response? How about creating integration tests dependent on some vendor service that you don't have a test environment for? These are the sort of things that mountebank can help solve.

MB runs on node.js, so it's simplest to intall it using with node package manager, though there is a separate install. I won't rehash the installation and first steps outlined in "Getting Started" of the MB documentation. To summarize it though, once you get it installed with npm, you can start it with the command 'mb' from the command line and see it working by putting "http://localhost:2525" into a browser. by default the api runs on port 2525. What the browser shows is the same documentation as is at the mountebank site.


Mountebank uses "imposters" to listen on a given port and react to requests with programmed responses. I say "programmed responses" as opposed to canned responses because, as we will see, there is a good deal of lattitude in supplying a response to any given request. 

Each imposter can have one to many stubs. A stub is a mapping of a request to a set of responses. A stub uses predicates to match against the incoming request. The predicate defines a set of information and if the incoming request matches the incoming request, then the next response in the set of responses defined for the stub is returned back to the caller. The set of responses is circular: MB takes the next response in line, returns it, and then puts that response to the back of the line. In this way you can impersonate a service that returns different responses for the same request.

To summarize the basic workings of using mountebank when testing, in your test setup (or test fixture) you start the MB API, then add an imposter and stub, make a request to the imposter service and then evaluate the response it returns.

In our projects we are generally handling applications for credit cards. One of our downstream services is a vendor who makes the decision on whether an application qualifies for a card, what sort of card, and how big of a credit line. We use MB to "fill-in" for the outside vendor service. We can use predicates to match on the (fake) social security number on an application, or the user's income, for example, and return any of a number of responses based on what our vendor would actually send.

In my next post, I'll actually demonstrate a service under test along with the related setup for some MB imposters.

There is a .Net library for utilizing the MB API out there called MbDotNet. I tried it out, but off the bat saw that it wasn't going to be adequate for the testing I wanted to do. You may have more luck. It's definitely a project I would be interested in contributing to, because I'm a true believer in using MB, and would love to make it easier for .Net devs.

Mountebank Config File Issue and a Lesson At My Expense

tl;dr: Back up your stuff, and you have to create mountebank config files in something other than VisualStudio.

Okay, the first lesson to dole out for the day is to back up your blog entry drafts as you write them. I am currently going back through some projects we have been working on cleaning up and reworking tests to get better coverage (and finding some issues along the way, which has made this a very worthwhile excercise). In trying to get some tests working locally, I discovered they rely on mountebank, an incredibly handy code package that acts as a test double for downstream services. Tests were failing because I hadn't reinstalled mountebank locally since I had a crash about six weeks ago. 

So, I got mountebank re-installed. Some of the tests needed to be re-worked so. In doing so I ran into an extremely frustrating issue where MB just won't accept a configuration file. I was working from home, so my wife was suddenly an audience for the flood of expletives I can unleash at times while doing this job. After her admonishment and composing myself I realized I had run into this exact smae issue before. More on this later. I remembered I had even written down the exact nature of the issue before. I set about tryiing to find just exactly what had happened to what I wrote.

I remember thinking that it would make for a good blog post. Looking at my published blog posts, however, turned up nothing. Had I just saved it locally and then never published it? The crash I mentioned before was actually an issue with our corporate encryption software. Basically every file that I had created locally had been encrypted by the software, which then suddenly stopped recognizing that I was who I said I was and wouldn't decrypt anything. This included config files for software I used every day, which all then stopped working. Anyway, long story short, I lost basically everything I had written and only saved locally.

At one point I had sent out some notes to my fellow teammates on using mountebank. Maybe I had included my write-up for them. One sent me back that email, which included a couple links on getting started with MB, along with a note saying "I was looking forward to reading your blog post on it."  Argh!

So here I am re-creating that post along with the lesson for all to save those blog posts as drafts online, or somewhere where they will eventually be lost to corporate encryption perdition.

I'm going to make this a series of posts, building incrementally, since there is a lot of depth to mountebank that can be explored. With that in mind, I want to wrap this initial post up with a rundown of the problem I ran into once again yesterday,

You can begin running the mountbank API simply with the command 'mb' on the command line and then making a series of posts to it to set up the services you intend to impersonate. I've found for automated testing purposes it is simpler to pass a configuration file as an .ejs file. 

mb --configfile "C:/path/to/my/config.ejs"

The .ejs extension allows you to use javaScript and javaScript variables directly in the file, something to explore later. The issue is when you create this .ejb file in VisualStudio, VS does something to add additional info to the file which causes MB to choke on the file. MB will throw an error that the JSON in the file is incorrect. You will then spend the next half hour looking for stray brackets or misplaced commas and then copying in the content of previously-created files that work just fine and pulling out your hair.

Then you will try opening the file in a text editor like Notepad++ and re-copying the contents in, to discover that doesn't work either. Then you'll check to confirm that the .ejs file is being copied to the correct location upon build. You have to delete the file and re-create it in something other than VS. Notepad++ works just fine. I'm not sure if VS Code works. I've discovered now that this is an issue with both VS 2015 and VS 2017 (since my rebuild of the computer now has the latest VS).

Hope this helps out some of you to save both time and hair. My next post will hopefully get one at least started using mountebank for testing purposes.