Something is wrong here—that was a lot of setup! The general-purpose FakeCondor replicates too much functionality from the full class. The researchers' puppet didn't scavenge its own carrion, so why should ours? We just want to test that the baby Eats. We condense various motherhood behaviors, such as giving food, into single method calls by extracting a role interface. (If we couldn't change Condor, we would also write an adapter.)

class CondorMotherhoodRoleInterface {
 public:
  virtual Carrion* GiveFood() = 0;
  virtual SomeReturnTypes* OtherMomBehaviors() = 0;
};


Then we write a single-use fake which provides only behaviors we need for this particular test.

class CondorFeedingPuppet: public CondorMotherhoodRoleInterface {
 public:
  virtual Carrion* GiveFood() { return test_carrion_; }
  virtual SomeReturnTypes* OtherMomBehaviors() { return NULL; }
  Carrion* test_carrion_; // public var is tolerable in a one-off object
};

TEST_F(BabyCondorTest, EatsCarrion) {
  CondorFeedingPuppet mother; FakeCarrion test_carrion;
  mother.test_carrion_ = &test_carrion;
  chick_.ReceiveFood(&mother);
  chick_.Eat();
  EXPECT_TRUE(test_carrion.WasEaten());
}


This highly-focused fake is easy and quick to write, and makes the test much simpler and more readable. Don't overestimate the complexity of your dependencies! Often a very simple fake is the best.



It is pretty easy to mock this interface. Still, every mock has to implement all three methods, even if you only need one. You also need a separate mock for each set of inputs. With EasyMock, you can create mocks as you need them, recording and replaying your expectations:

public void testAtmLogin() {
  Atm mockAtm = createMock(Atm.class); // 1
  EasyMock.expect(mockAtm.enterAccount("MyAccount")).andReturn(true); // 2
  EasyMock.expect(mockAtm.enterPin("1234")).andReturn(true); // 3
  EasyMock.replay(mockAtm); // 4
  Account account = new Account();
  account.login(mockAtm); // 5
  assertTrue(account.isLoggedIn());
  EasyMock.verify(mockAtm); // 6
}


We tell EasyMock to create a dynamic proxy implementing Atm (1), which starts in record mode. Then we record two method calls along with the expected results (2 and 3). The replay() call tells EasyMock to stop recording (4). After that, calls on the object return the set values. If it gets a call it does not expect, it throws an Exception to fail fast. Account now uses the mock as if it were the real thing (5). The verify() method checks to see if the mock actually received all the calls you expect (6). It really is that simple. If we want to simulate failure, we can set up another test to return false from one of the method calls.

EasyMock has lots more capabilities as well. It can throw exceptions. It also can record multiple calls to the same method returning the same or different results. You also can create stub expectations and nice mocks so you don't have to record every expected call. You also can create several mocks, and even nest them to test classes with complex dependencies. Beware, though, this often creates brittle tests, and is a sign the class under test needs refactoring.

Basic EasyMock only mocks interfaces, but there is an EasyMockClassExtension that mocks non-final classes when you really must. See the EasyMock documentation at the link below for details.

There are two different kind of situations you can get yourself into:

  1. Either your code calls a third-party library (such as you calling into LDAP authentication, or JDBC driver)

  2. Or a third party library calls you and forces you to implement an interface or extend a base class (such as when using servlets).

Unless these APIs are written with testability in mind, they will hamper your ability to write tests.

Calling Third-Party Libraries

I always try to separate myself from third party library with a Facade and an Adapter. Facade is an interface which has a simplified view of the third-party API. Let me give you an example. Have a look at javax.naming.ldap. It is a collection of several interfaces and classes, with a complex way in which you have to call them. If your code depends on this interface you will drown in mocking hell. Now I don't know why the API is so complex, but I do know that my application only needs a fraction of these calls. I also know that many of these calls are configuration specific and outside of bootstrapping code these APIs are cluttering what I have to mock out.

I start from the other end. I ask myself this question. 'What would an ideal API look like for my application?' The key here is 'my application' An application which only needs to authenticate will have a very different 'ideal API' than an application which needs to manage the LDAP. Because we are focusing on our application the resulting API is significantly simplified. It is very possible that for most applications the ideal interface may be something along these lines.
interface Authenticator {
 boolean authenticate(String username,
                      String password);
}

As you can see this interface is a lot simpler to mock and work with than the original one as a result it is a lot more testable. In essence the ideal interfaces are what separates the testable world from the legacy world.

Once we have an ideal interface all we have to do is implement the adapter which bridges our ideal interface with the actual one. This adapter may be a pain to test, but at least the pain is in a single location.

The benefit of this is that:

  • We can easily implement an InMemoryAuthenticator for running our application in the QA environment.

  • If the third-party APIs change than those changes only affect our adapter code.

  • If we now have to authenticate against a Kerberos or Windows registry the implementation is straight forward.

  • We are less likely to introduce a usage bug since calling the ideal API is simpler than calling the original API.

Plugging into an Existing Framework

Let's take servlets as an example of hard to test framework. Why are servlets hard to test?

  • Servlets require a no argument constructor which prevents us from using dependency injection. See how to think about the new operator.

  • Servlets pass around HttpServletRequest and HttpServletResponse which are very hard to instantiate or mock.

At a high level I use the same strategy of separating myself from the servlet APIs. I implement my actions in a separate class
class LoginPage {
 Authenticator authenticator;
 boolean success;
 String errorMessage;
 LoginPage(Authenticator authenticator) {
   this.authenticator = authenticator;
 }

 String execute(Map<String, String> parameters,
                String cookie) {
   // do some work
   success = ...;
   errorMessage = ...;
 }

 String render(Writer writer) {
   if (success)
     return "redirect URL";
   else
     writer.write(...);
 }
}

The code above is easy to test because:

  • It does not inherit from any base class.

  • Dependency injection allows us to inject mock authenticator (Unlike the no argument constructor in servlets).

  • The work phase is separated from the rendering phase. It is really hard to assert anything useful on the Writer but we can assert on the state of the LoginPage, such as success and errorMessage.

  • The input parameters to the LoginPage are very easy to instantiate. (Map<String, String>, String for cookie, or a StringWriter for the writer).

What we have achieved is that all of our application logic is in the LoginPage and all of the untestable mess is in the LoginServlet which acts like an adapter. We can than test the LoginPage in depth. The LoginSevlet is not so simple, and in most cases I just don't bother testing it since there can only be wiring bug in that code. There should be no application logic in the LoginServlet since we have moved all of the application logic to LoginPage.

Let's look at the adapter class:
class LoginServlet extends HttpServlet {
 Provider<LoginPage> loginPageProvider;

 // no arg constructor required by
 // Servlet Framework
 LoginServlet() {
   this(Global.injector
          .getProvider(LoginPage.class));
 }

 // Dependency injected constructor used for testing
 LoginServlet(Provider<LoginPage> loginPageProvider) {
   this.loginPageProvider = loginPageProvider;
 }

 service(HttpServletRequest req,
         HttpServletResponse resp) {
   LoginPage page = loginPageProvider.get();
   page.execute(req.getParameterMap(),
        req.getCookies());
   String redirect = page.render(resp.getWriter())
   if (redirect != null)
     resp.sendRedirect(redirect);
 }
}

Notice the use of two constructors. One fully dependency injected and the other no argument. If I write a test I will use the dependency injected constructor which will than allow me to mock out all of my dependencies.

Also notice that the no argument constructor is forcing me to use global state, which is very bad, but in the case of servlets I have no choice. However, I make sure that only servlets access the global state and the rest of my application is unaware of this global variable and uses proper dependency injection techniques.

BTW there are many frameworks out there which sit on top of servlets and which provide you a very testable APIs. They all achieve this by separating you from the servlet implementation and from HttpServletRequest and HttpServletResponse. For example Waffle and WebWork
1 comment