Database TDD Part 17: Mocking Access

by Jeff Langr

November 04, 2005

I have a failing test due to database dependencies:

    package application;
    
    import junit.framework.*;
    
    public class ApplicationTest extends TestCase {
       public void testVerifyUser() {
          final String name = "name";
          final String password = "password";
          Application application = new Application();
          assertFalse(application.isRegistered(name, password));
          application.registerUser(name, password);
          assertTrue(application.isRegistered(name, password));
       }
    }

I want to use an implementation of the UserAccess class that exists solely for controlling tests against Application. In the test, I introduce a setter method call to drop in a mock UserAccess implementation (to be defined):

       public void testVerifyUser() {
          final String name = "name";
          final String password = "password";
          Application application = new Application();
          application.setUserAccess(new MockUserAccess());
          assertFalse(application.isRegistered(name, password));
          application.registerUser(name, password);
          assertTrue(application.isRegistered(name, password));
       }

The Application class must change to accommodate this test intrusion:

    package application;
    
    import domain.*;
    
    public class Application {
       private UserAccess userAccess = new UserAccess();
    
       public void registerUser(String name, String password) {
          User user = new User(name, password);
          userAccess.save(user);
       }
    
       public boolean isRegistered(String name, String password) {
          User user = userAccess.find(name);
          return user != null;
       }
    
       void setUserAccess(UserAccess userAccess) {
          this.userAccess = userAccess;
       }
    }

I’d consider annotating the setUserAccess method with a comment saying it’s designed for testing use–but only if someone mentioned it.

The mock class is really dumb at this point. Its needs are minimal based on the existing content of ApplicationTests. The class will need to change as I add more comprehensive tests against Application.

    package application;
    
    import persistence.*;
    import domain.*;
    
    public class MockUserAccess extends UserAccess {
       private static User user;
       public User find(String key) {
          return MockUserAccess.user;
       }
    
       public void save(Persistable persistable) {
          MockUserAccess.user = (User)persistable;
       }
    }

Subclass-based mocks can introduce some interesting issues. You do have to have a clear understanding of the behavior of the superclass, otherwise you run the risk of side effects whacking your tests. It’s generally safer to not go with this approach. Here, the benefit is that I don’t have to implement the unused PersistableMetadata methods.

Is this mocking tactic scaleable? What about when the Application class has to work with half a dozen persistence APIs? Do we want half a dozen setter methods used solely for the test? It’s too early for me to tell or even care.

The DataAccess subclasses, UserAccess and CustomerAccess, are still being tested using live JDBC calls. My take: that’s a good thing. It’s too easy for code to get out of sync with the database under test. If you have a few dozen DataAccess subclasses, perhaps they fall into the category of “integration’ tests. I’m not compelled to give them a Meaningful Name like that. But if they get in the way–if they start bogging things down in terms of execution time–I’ll foist them into a test suite that gets run just a bit less frequently. And, at that time, come up with a trustworthy mechanism to demonstrate that DataAccess subclasses and the Persister class are correctly coordinating with each other.

For now, I’m comfortable knowing that I could begin to build the rest of the application class in advance of any persistence details.

Share your comment

Jeff Langr

About the Author

Jeff Langr has been building software for 40 years and writing about it heavily for 20. You can find out more about Jeff, learn from the many helpful articles and books he's written, or read one of his 1000+ combined blog (including Agile in a Flash) and public posts.