Stubs

A stub is another example of a fake object. We can use stubs when we have some dependencies in the subject under test that need to be satisfied with an object that returns a value. They can also be used to provide a bulkhead to stop computationally expensive or I/O reliant functions from being run.

Stubs can be implemented in much the same way that we implemented spies. We just need to intercept the call to the method and replace it with a version that we wrote. However, with stubs we actually don't call the replaced function. It can be useful to keep the replaced function around just in case we need to restore the functionality of the stubbed out class.

Let's start with an object that depends on another object for part of its functionality:

class Knight {
  constructor(credentialFactory) {
    this.credentialFactory = credentialFactory;
  }
  presentCredentials(toRoyalty) {
    console.log("Presenting credentials to " + toRoyalty);
    toRoyalty.send(this.credentialFactory.Create());
    return {};
  }
}

This knight object takes a credentialFactory argument as part of its constructor. By passing in the object we exteriorize the dependency and remove the responsibility for creating credentialFactory from the knight. We've seen this sort of inversion of control previously and we'll look at it in more detail in the next chapter. This makes our code more modular and testing far easier.

Now when we want to test the knight without worrying about how a credential factory works, we can use a fake object, in this case a stub:

class StubCredentialFactory {
  constructor() {
    this.callCounter = 0;
  }
  Create() {
    //manually create a credential
  };
}

This stub is a very simple one that simply returns a standard new credential. Stubs can be made quite complicated if there need to be multiple calls to it. For instance, we could rewrite our simple stub as the following:

class StubCredentialFactory {
  constructor() {
    this.callCounter = 0;
  }
  Create() {
    if (this.callCounter == 0)
      return new SimpleCredential();
    if (this.callCounter == 1)
      return new CredentialWithSeal();
    if (this.callCounter == 2)
      return null;
    this.callCounter++;
  }
}

This version of the stub returns a different sort of credential every time it is called. On the third call it returns null. As we set up the class using an inversion of control, writing a test is as simple as the following:

var knight = new Knight(new StubCredentialFactory());
knight.presentCredentials("Queen Cersei");

We can now execute the test:

var knight = new Knight(new StubCredentialFactory());
var credentials = knight.presentCredentials("Lord Snow");
assert(credentials.type === "SimpleCredentials");
credentials = knight.presentCredentials("Queen Cersei");
assert(credentials.type === "CredentialWithSeal");
credentials = knight.presentCredentials("Lord Stark");
assert(credentials == null);

Because there is no hard typing system in JavaScript, we can build stubs without worrying about implementing interfaces. There is also no need to stub an entire object but only the function in which we're interested.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset