Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing: coding to interfaces?

Currently my project is composed of various concrete classes. Now as I'm getting into unit testing it looks like I'm supposed to create an interface for each and every class (effectively doubling the number of classes in my project)? I happen to be using Google Mock as a mocking framework. See Google Mock CookBook on Interfaces. While before I might have just classes Car and Engine, now I would have abstract classes (aka C++ interfaces) Car and Engine and then the implementation classes CarImplementation and EngineImpl or whatever. This would allow me to stub out Car's dependency on Engine.

There are two lines of thought I have come across in researching this:

  1. Only use interfaces when you may have the need for more than one implementation of a given abstraction and/or for use in public APIs, so otherwise don't create interfaces unnecessarily.

  2. Unit tests stubs/mocks often are the "other implementation", and so, yes, you should create intefaces.

When unit testing, should I create an interface for each class in my project? (I'm leaning towards creating interfaces for ease of testing)

like image 632
User Avatar asked Jul 08 '11 01:07

User


People also ask

How interface is used in unit testing?

To test an interface with common tests regardless of implementation, you can use an abstract test case, and then create concrete instances of the test case for each implementation of the interface.

Does unit testing require coding?

Unit tests are typically isolated to ensure a unit does not rely on any external code or functions. Testing can be done manually but is often automated.


1 Answers

Think you've got a number of options. As you say, one option is to create interfaces. Say you have classes

class Engine:
{
public:
    void start(){ };
};

class Car
{
public: 
    void start()
    {
        // do car specific stuff
        e_.start();

private:
    Engine e;
};

To introduce interfaces - you would have to change Car to take an Engine

class Car
{
public: 
    Car(Engine* engine) :
    e_(engine)
    {}

    void start()
    {
        // do car specific stuff
        e_->start();

private:
    Engine *e_;
};

If you've only got one type of engine - you've suddenly made your Car objects harder to use (who creates the engines, who owns the engines). Cars have a lot of parts - so this problem will continue to increase.

If you want seperate implementations, another way would be with templates. This removes the need for interfaces.

class Car<type EngineType = Engine>
{
public: 
    void start()
    {
        // do car specific stuff
        e_.start();

private:
    EngineType e;
};

In your mocks, you could then create Cars with specialised engines:

Car<MockEngine> testEngine;

Another, different approach, would be to add methods to Engine to allow it to be tested, something like:

class Engine:
{
public:
    void start();
    bool hasStarted() const;
};

You could then either add a check method to Car, or inherit from Car to test.

class TestCar : public Car
{
public:
    bool hasEngineStarted() { return e_.hasStarted(); }
};

This would require Engine to be changed from private to protected in the Car class.

Depending on the real world situation, will depend on which solution is best. Also, each developer will have their own holy grail of how they believe code should be unit tested. My personal views is to keep the client/customer in mind. Lets assume your clients (perhaps other developers in your team) will be creating Cars and don't care about Engines. I would therefore not want to expose the concepts of Engines (a class internal to my library) just so I can unit test the thing. I would opt for not creating interfaces and testing the two classes together (third option I gave).

like image 162
Will Avatar answered Sep 23 '22 09:09

Will