tags:

views:

109

answers:

1

I'm trying to make extensive tests for my new project but I have a problem.

Basically I want to test MyClass. MyClass makes use of several other class which I don't need/want to do their job for the purpose of the test. So I created mocks (I use gtest and gmock for testing)

But MyClass instantiate everything it needs in it's constructor and release it in the destructor. That's RAII I think.

So I thought, I should create some kind of factory, which creates everything and gives it to MyClass's constructor. That factory could have it's fake for testing purposes. But's thats no longer RAII right?

Then what's the good solution here?

+1  A: 

You mock it the same way you'd mock any other class. Have the RAII class' constructor take care of it.

class MyInterface
{
    virtual void MyApiFunction(int myArg)
    {
        ::MyApiFunction(myArg);
    }
};

class MyRAII : boost::noncopyable //Shouldn't be copying RAII classes, right?
{
    MyInterface *api;
public:
    MyRAII(MyInterface *method = new MyInterface)
    : api(method)
    {
        //Aquire resource
    }
    ~MyRAII()
    {
        //Release resource
        delete api;
    }
};

class MockInterface : public MyInterface
{
    MOCK_METHOD1(MyApiFunction, void(int));
};

TEST(Hello, Hello)
{
    std::auto_ptr<MockInterface> mock(new MockInterface);
    EXPECT_CALL(*mock, ....)...;
    MyRAII unitUnderTest(mock.release());
}
Billy ONeal
I suppose the default value for method is what makes it ok in a RAII context here ... But it creates a dependency on MyInterface for MyRAII users.
f4
@f4: Well, MyRAII depends on MyInterface. How do you expect otherwise? You can hide it with a default argument or you can hide it with multiple constructors. But MyRAII needs to be able to get your mock class somehow. Changing to a factory method doesn't solve the problem -- your factory method still then needs to know which one to make.
Billy ONeal
I meant users of MyRAII. They don't have to know MyRAII uses MyInterface, and they don't need to depend on MyInterface.h. Doing so there has to be a #include "MyInterface.h".About the factory I wrote "That factory could have it's fake for testing purposes.". It would Create Mocks instead of real objects and give them to MyRAII constructor.Don't get me wrong I like your solution I was just concerned about the (physical) dependency it implies on MyInterface. I feel like it's unveiling some of the inner workings of MyRAII :) and I'm trying to avoid unnecessary includes.
f4
@f4: How does the factory know that you want mocks instead of the real deal? How do you get the mock back out of your RAII class so that you can use EXPECT_CALL.... on it? You can't, without adding some form of dependency of your class on that interface. Making the class in a factory does not help you. If you're concerned about adding extra headers, then put the definition for the interface inside the same header as your class. A mocked interface like this should be simple enough that it does not significantly affect compilation time.
Billy ONeal
yeah I know the factory has the same 'problem'. And no I'm not really concerned by compilation time. This project isn't big enough for it to really matter. I'm just trying to teach me good practices before I really need it!
f4
@f4: Good practices is not "NO HEADER FILES CAN INCLUDE OTHER HEADERS". You don't want to have every source file including every header under the sun, but headers need to include headers. Avoiding a dependency like this is unrealistic. Best practices is not necessarily including fewer headers; but including no more than necessary.
Billy ONeal