Mocking System APIs

One problem a lot of people run into is the need to test code that uses APIs they don’t control. This came up tonight during a discussion on mocking at the Pillar Technology Plugged In event in Ann Arbor. The system in question was a remote service, but I encountered it recently with UNIX system calls. Fortunately there’s a simple solution.

If you wrap the APIs in a class, you can mock that class. I’ll show you an example from my own project, written in C++. The first step was to create an interface. In classes that need to access this API, they will declare a member which is a pointer to that interface.

```C++ class DirectoryInterface {

public:

virtual void OpenDir(const char*) = 0;
virtual struct dirent* readdir() = 0;
virtual bool is_regular_file(const char *) = 0; }; ```

In my test suite, I create a mock (using Google Mock).

C++ class MockDirectory : public DirectoryInterface { public: MOCK_METHOD1(OpenDir, void(const char*)); MOCK_METHOD0(readdir, struct dirent*()); MOCK_METHOD1(is_regular_file, bool(const char*)); };

Now in my test suite setup, I can inject the mock into my FileFolder object. I’ll also take this opportunity to set up some default behavior that I want to be true across all of my tests.

```C++ class testFileFolder : public testing::Test { public: FileFolder *folder;

NiceMock<MockDirectory> directory;

virtual void SetUp() {
    folder = new FileFolder(".", &directory);

    ON_CALL(directory, is_regular_file(StrEq(FILE_1)))
            .WillByDefault(Return(true));
    ON_CALL(directory, is_regular_file(StrEq(DIRECTORY_1)))
            .WillByDefault(Return(true));
} } ```

Now later on in a test, when I need to check how the FileFolder object interacts with the the Directory object, I can test that the FileFolder methods are making the right calls into the Directory interface, and control what the Directory interface returns to the FileFolder methods.

```C++ TEST_F(testFileFolder, files_withOneRegularFile_willPutFileInList) { // There will be an error is OpenDir is not called EXPECT_CALL(directory, OpenDir(_));

// There will be an error if readdir is not called
EXPECT_CALL(directory, readdir())
            .WillOnce(Return(&ent_file_1)); // when it is called, it should return ent_file_1

// Actually call the method we're trying to test
folder->Load();

// Check that the folder object has the expected state
ASSERT_THAT(folder->files.size(), Eq(1));
ASSERT_THAT(folder->files[0], StrEq(FILE_1)); } ```

This works especially well when you’re trying to test exception conditions. For instance I might want a test to ensure that I handle an unreadable or missing directory in a sane way. Instead of returning a value I could have just as easily thrown an exception, and written tests to ensure that the FileFolder object responded in the way I want.

In fact testing around error conditions is one of the most valuable things you can do with Test Driven Development. If for each API call you put in, you write a test around its possible error conditions, you’ll have a lot fewer bugs and production support calls.

Clay Dowling

Consultant, Programmer, Woodworker, unashamed cat guy.

Dexter, MI, USA claydowling.com