Nocking

I’m pretty into mocking…though I went overboard years ago when I really first started implementing it in my tests. Now-a-days I keep it under control, really only mocking external services. If I must mock part of my own API (e.g. for performance reasons) I make sure I minimize the mocks per test.

In Python I’ve extensively used the mock and request-mock packages.  They’re great, but I find their APIs a bit clunky. Lately I’m doing more Node.js and needed to mock an HTTP request and response.

Wow, it really can’t get much easier and cleaner than the nock package. It offers a real intuitive API that allowed me to write a non-trivial test in a few minutes, simply looking at this post. This tests a command-line program which takes an argument that’s a URL to a text file. The text file the URL argument points to contains a new-line separated list of other URLs to process.

Specifically this is testing the program’s getURLs method which is responsible for figuring out what URLs to process. The method is actually a bit more complex than I made it out to be, thus the need for testing. Here goes:

...
it("returns array of urls from a URL", async done => {
    // The `Cli` class takes as 
    // parameters a `runner` 
    // and a `commander` instance
    // (a command-line argument 
    // processing class). 

    // Fake out the runner and commander
    // object so we don't have to 
    // actually run this on the 
    // command-line. Do this with 
    // simple fake objects, not nock.
    const fakeRunner = {};

    // Pretend we are passing a URL 
    // to a text file by setting the 
    // args property of the fake commander
    // object.
    const fakeCommander = { args: ["http://example.com/foo.txt"] };
    const cli = new Cli(fakeCommander, fakeRunner);

    // Mock the HTTP request and response 
    // to and from the URL containing the 
    // new-line separated URLs.
    nock("http://example.com")
      .get("/foo.txt")
      .reply(200, 
          "http://example.com\nhttp://example.com/foo"
    );

    // We should get back the URLs contained 
    // in the remote text file.
    expect(["http://example.com", "http://example.com/foo"]).toEqual(
      await cli.getURLs()
    );
    done();
  });
...

Leave a Reply

Your email address will not be published. Required fields are marked *