3

I want to test an abstract class with:

  1. Pure virtual methods that should be overridden in sub-classes
  2. Non-pure virtual methods that use the pure virtual methods (as opposed to this question)
class Fu
{
  public:
    virtual void func(int count, std::string data)
    {
        for(int i = 0; i < count; i++)
        {
            pureFunc(data);
        }

    }
    virtual void pureFunc(std::string data) = 0;
}

Now to test func, I want to make sure that it calls pureFunc count times with argument data. What I have done is to subclass Fu and also create a Mock:

class TestFu : public Fu
{
  public:
    virtual void pureFunc(std::string data) override {};
}

class MockFu : public TestFu
{
  public:
    MOCK_METHOD1(pureFunc, void(std::string));
}

And to test I do the following:

MockFu mock_fu;
EXPECT_CALL(mock_fu, pureFunc("test"))
.Times(10);

mock_fu.func(10, "test");

However I was wondering if the above is a valid pattern. My worry is that I am testing the mock class as opposed to the class or it's non-abstract sub-class.

To sum up:

  1. Is the above pattern valid? If yes is it ok that I am testing a mock object? If no how do I achieve my goal?
  2. In general is it valid practice to mock some parts of a class to unit test other parts? If so what is the common practice to do so?

1 Answer 1

3

You are asking quite a few things here, but let me share my opinion on the things you describe.

The typical use of mock classes is when you need them for testing another class, and need to check if the state of the mock class is changed (instead of more heavy implementations of the interface).

The case that you describe is valid of course, but I would like to argue that the test in itself is not useful. In a typical example I would expect pureFunc to be private, but it does not matter too much. What you are actually testing now is implementation, and not the behavior. What you should test is what func does (i.e., by returning something or changing the state of the class).

To be more explicit. In your example I can have the for-loop in func run to count/2 and run the code in pureFunc itself twice (doesn't work for odd numbers, but consider it for the sake of the argument. The unit test fails, however, the state of your object is the same. You want to be able to change your class and implementation, without unit tests starting to fail. If you need to modify the unit test everytime you change the implementation, you have done something wrong.

So what can you do instead? Well, you have implementations of your abstract class. You can test func for that, to check if it does what you expect. (And pureFunc if it is really public).

2
  • Thank you for your answer. If I may ask a follow up: - when unit testing. do we consider the class as one unit or it's methods? if methods then shouldn't we mock some methods to be able to test other ones in isolation? - In my case it is part of the criteria that pureFunc is called n times. It is a callback function that is called with every data packet received. So really the purpose of func is to parse received data and pass it to pureFunc. How can I test that functionality without mocking pureFunc?
    – pooya13
    Feb 22, 2019 at 18:34
  • I don't know enough about your design to be certain. It sounds that your class has too many responsibilities. Maybe purefunc should be in a separate class that is mocked, and for that you can test the amount of calls. In general I'd call a class a unit, and try to test the class in isolation via the public interface.
    – Bernhard
    Feb 23, 2019 at 6:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.