Well, we finally got tired of over engineering 2 lines of code just to make it testable. I’m talking about those classes which have some http calls done throughout some code; intermingled with maybe some error handling, some conditional logic, etc ..

In other words, you want to test everything around the http call, but don’t care about the call actually being made or not. Yes, yes, yes. I know; just abstract out the call to another class, then mock that … pain in the ass! Use Spring rest template. Pain in the ass and overkill and doesn’t work well in multi threaded setups.

The solution we now use here is called NanoHTTPD which is a tiny, tiny, miniscule http server which can easily run inside a suite of tests. It can easily be extended to intercept calls. For example, we have:

  • A HitCountingNanoHTTPD implementation which counts how many times the server was hit (good for testing that a multi-threaded class actually does the amount of call outs you need)
  • Another implementation that given a file with key value pairs, will set the response headers using that file.
We use it in the following way:
class HttpHitTest {
     private NanoHTTPD nano;

     @Before
     public void setup() throws Exception {
          nano = new Nano(9999);
     }

     @After
     public void tearDown() throws Exception {
          nano.stop();
     }

     @Test(expected=NoSuchFileException.class)
     public void testHttpHit() {
           HttpGetClass hgc = new HttpGetClass();
           hgc.doGet("http://localhost:9999/resources/myfile.mp3");
      }
}

See the beauty! NanoHTTPD simply exposes all files found in it’s working directory. So all test resources simply go into a folder inside the project and the CI server runs it without a hitch. Bonus: test performance and speeds are not affected (this thing is just so tiny).

As well, here’s what an extension to NanoHTTPD would look like. This example is a very simple something I whipped up to count how many times a server is hit (I needed the counter to be thread safe)

public class HitCountingNanoHttpd extends NanoHTTPD {
	private AtomicLong hits = new AtomicLong(0);
	
	public HitCountingNanoHttpd(int port) throws IOException {
		super(port);
	}
	
	@Override
	public Response serve(String uri, String method, Properties header, Properties parms, Properties files) {
		hits.incrementAndGet();
		return super.serve(uri, method, header, parms, files);
	}
	
	public long getHitCount() {
		return hits.longValue();
	}
}