How to move mocked method without breaking unit tests

61 views
Skip to first unread message

David Wallace

unread,
Feb 25, 2016, 9:35:15 PM2/25/16
to Google C++ Mocking Framework
This is a problem that may start with a possible "abuse" of gmock.  I've got a legacy class, TraceObjTab, that I've written a bunch of unit tests for. There's a short stretch of code deep in the guts of TraceObjTab's methods that isn't practical to execute in the unit test environment, so I've refactored that into a short method, create_cdc_record, that I can mock out in a testing subclass of TraceObjTab:

class TestingTraceObjTab : public TraceObjTab{
public:
...
MOCK_METHOD1(create_cdc_record,
void(CdcClockSource&));
...
};

Note that this is basically a fully functional object, with one mock method - the rest of the TraceObjTab code is still live except for a couple of other methods that I've overridden for testing purposes (this is the gmock "abuse" I mentioned above, since it's not really a mock object).

All I care about for the unit test purposes is how many times this functionality gets called, so I currently do that with an expectation on this method, e.g.:
TestingTraceObjTab tab1(...);
EXPECT_CALL(tab1, create_cdc_record(_)).Times(1);

Now the problem is that I want to move the method that calls create_cdc_record from a method of TraceObjTab to a method of CdcClockSource.  Both the code in that method, and the code in create_cdc_record, are interacting primarily with the instance variables of CdcClockSource (which is currently the only argument to both methods), so the code more naturally belongs there. There may be several CdcClockSources created over the lifetime of the TraceObjTab.  What I want to do is count how many times they collectively call the functionality in create_cdc_record, without actually executing that functionality in the test environment.

Some approaches I've considered:
1) Keep create_cdc_record as a method of TraceObjTab, and pass it as a callback to each CdcClockSource.  This maintains compatibility with my existing tests, but entangles the implementation of the two classes just to make testing of the TraceObjTab class a little easier.  As I said, both methods really belong in CdcClockSource.

2) Move the create_cdc_record_method to CdcClockSource, but find some way to disable the create_cdc_record functionality and keep a count of the total calls in the test environment.  Mocking out the method here as I did tor the TestingTraceObjTab doesn't necessarily seem appropriate, since I wouldn't know how many times each individual object should call the method.   So possibly something like:
  a) Extract the creation of CdcClockSources into a factory method in TraceObjTab, so that I can override it in TestingTraceObjTab to return a TestingCdcClockSource, that subclasses CdcClockSource.
  b) Change the current mock create_cdc_record method in TestingTraceObjTab to a method that increments a counter in TestingTraceObjTab, and update the tests to check the value of the counter at the end of the test instead of using EXPECT_CALL.
 c) Pass that counter by reference to the TestingCdcClockSources created by that overridden factory method from (a).
 d) After moving create_cdc_record and its caller to CdcClockSource, override it in TestingCdcClockSource to increment the counter as in (b).

After writing this out here, I'm thinking that #2 is probably the best way to go, although it may make the test code harder to understand.  Are there other approaches people recommend or things that I've overlooked here?

Dave W.
Reply all
Reply to author
Forward
0 new messages