Comparing googlemock to Mocha

mocha artHigher-level languages are great, but every now and then I like some good old C++. So I was a bit excited when I got the chance to use C++ recently on a piece of demo software. After spending a lot of time in Ruby and Javascript (or more accurately, Coffeescript), it was both comforting and frustrating to be back in the land of pointers, memory allocation, and static types.

Since this code was meant for a demo, it was originally written to be throw-away. Moreover, since it was leveraging a large codebase which did not have any establisted testing framework – or tests of any kind – I made the decision to just get the code working and forget about writing test suites. And then, of course, the situation changed. Suddenly the code needed to be solid enough to pass off to someone else and have them run with it. In my four months at Atomic Object, I’ve already absorbed enough of Atomic’s philosophy that the thought of my code persisting in someone else’s hands without any tests was cringe-inducing. Having done nearly all of my testing in RSpec (with Mocha) and a little Jasmine, I wasn’t optimistic that I could find something that easy for C++. I wanted something that would provide straightforward mocking capabilities so I could perform true unit tests.

After a relatively quick search, I landed on googletest, plus googlemock as a mocking framework. Maybe it was because they have an introductory page labelled “For Dummies“, but I think it came down to the structure being straightforward and familiar to me. For example, this Mocha code:

mock_menu = mock 'fast food menu'
mock_menu.expect(:has_item?).with("liter of cola").returns(false)

looks something like this in C++ with googlemock:

MockIMenu *mockMenu = new MockIMenu();
EXPECT_CALL(*mockMenu, hasItem("liter of cola"))
  .WillOnce(Return(false));
// delete the mock - but thankfully googlemock will warn us if we miss this step
delete mockMenu;

It’s certainly not as elegant as Ruby, but given that it’s C++, I’d call that quite readable and practical.

In the course of writing the tests, I naturally found myself restructuring code to make it more modular, to make it have better separation of concerns. That showed me that using googlemock can encourage good design.

Here is another example:

Mocha:

mock_student = mock 'student'
mock_job_seeker = mock 'job seeker'
mock_company = mock 'company'
mock_student.expect(:graduate).returns(mock_job_seeker)
mock_company.expect(:application).with(mock_job_seeker).returns(:no_thanks)
 
school.matriculate(mock_student)

Googlemock:

MockIStudent mockStudent(); // no need to delete these later
MockIJobSeeker mockJobSeeker();
MockICompany = mockCompany();
{
  // the InSequence declaration makes googlemock require that
  // expectations in the same scope be executed in order
  InSequence dummy; 
  EXPECT_CALL(mockStudent, graduate())
    .WillOnce(Return(mockJobSeeker));
  EXPECT_CALL(mockCompany, application(mockJobSeeker))
    .WillOnce(Return(ENUM_no_thanks));
}
 
school->matriculate(&mockStudent);

One thing that really impressed me about googlemock was how it easy it is to make arbitrary parameter matchers. For starters, if you add

using ::testing::_;

you can use _ to match any parameter. But say I need to verify only part of the contents of an object parameter, and I don’t care about the rest. For example, the object represents a patient and I only care if the social security number matches. That’s as simple as:

MATCHER(MatchSSN, compSSN)
{
  return arg != NULL && strcmp(arg->getSSN(), compSSN) == 0;
}

where arg is always the name of the object being matched. You can use this like so:

EXPECT_CALL(mockInsurance, getPatientInfo(MatchSSN("123-45-6789"));

This will pass only when getPatientInfo receives a pointer to a Patient object that has 123-45-6789 as her social security number. Googlemock also lets you easily support some situations you just don’t run into in Ruby, such as output parameters. It’s very straightforward to mock setting an output param when a function is called on a mock object:

// when mockPatient.getHeightAndWeight is called, set the first arg to 175 (cm)
// and the second arg to 77 (kg)
EXPECT_CALL(mockPatient, getHeightAndWeight(_,_))
  .WillOnce(DoAll(SetArgPointee<0>(175),SetArgPointee<1>(77)));

The only real frustration I felt going from Mocha to googlemock was entirely due to limitations of the C++ language. Mainly I missed the ability to add expectations on existing, regular objects. This is quite handy in Ruby for example when mocking out reading the contents of a file or mocking out some other system call. On the flip side, not being able to do this encourages you to create thin object layers around those operations, which isn’t a bad idea in an environment like C++ where system-level calls can vary quite a bit by platform.

In summary, if you’re used to mocking objects in higher-level languages and find yourself developing C++, googlemock is definitely worth checking out.