Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question on using Fruit with Google Mock #25

Closed
durandj opened this issue Aug 26, 2016 · 2 comments
Closed

Question on using Fruit with Google Mock #25

durandj opened this issue Aug 26, 2016 · 2 comments

Comments

@durandj
Copy link

durandj commented Aug 26, 2016

I recently started tinkering with using Fruit to make my code more testable and decrease the dependencies between components. I'm currently using Google Mock for mocking components but I'm not sure how to combine Fruit with Google Mock. Here is a basic sample version of what I'm trying to do and hopefully someone will be able to point out what I'm missing or misunderstanding.

The basic idea for the example is that you have a Car that is being modeled and it has several components but the main one for this example is the Engine. The Engine provides three methods: start, stop, and getNumberOfCylinders. The Car provides a variety of methods but the three main ones here are the start, stop, printDiagnostics methods.

Please note that for the sake of brevity I've omitted some of the basics like includes, header guards, and namespaces.

engine.hpp

class Engine {
public:
    virtual void start(void) = 0;
    virtual void stop(void) = 0;
    virtual int getNumberOfCylinders(void) = 0;
};

v8.hpp

fruit::Component<Engine> getV8EngineComponent(void);

v8.cpp

using namespace fruit;

class V8Engine : public Engine {
public:
    INJECT(V8Engine(void)) = default;

    virtual void start(void) override {
        // do engine type stuff
    }

    virtual void stop(void) override {
        // do engine type stuff
    }

    virtual int getNumberOfCylinders(void) {
        return 8;
    }
};

Component<Engine> getV8EngineComponent(void) {
    return createComponent().bind<Engine, V8Engine>();
}

car.hpp

class Car {
public:
    // snip other methods
    virtual void start(void) = 0;
    virtual void stop(void) = 0;
    virtual void printDiagnostics(void) = 0;
    // snip more methods
};

saturn.hpp

fruit::Component<fruit::Required<Engine>, Car> getSaturnComponent(void);

saturn.cpp

using namespace fruit;

class Saturn : public Car {
private:
    Engine *engine_;

public:
    INJECT(Saturn(Engine *engine)) : engine_(engine) {
    }

    virtual void start(void) override {
        // setup the dashboard lights
        // make annoying dinging

        engine->start();
    }

    virtual void stop(void) override {
        engine->stop();

        // make more dinging noises if the headlights are on
    }

    virtual void printDiagnostics(void) override {
        // output some diagnostics

        // print is some internal function for printing information to the diagnostics port
        print("number of cylinders in engine: {}", engine->getNumberOfCylinders());

        // output more diagnostics
    }
};

Component<Required<Engine>, Car> getSaturnComponent(void) {
    return createComponent().bind<Car, Saturn>();
}

mock_engine.hpp

class MockEngine : public Engine {
public:
    MOCK_METHOD0(start, void(void));
    MOCK_METHOD0(stop, void(void));
    MOCK_METHOD0(getNumberOfCylinders, int(void));
};

test_saturn.cpp

using namespace fruit;

Component<Car> getTestCarComponent(Engine *engine) {
    return createComponent()
        .install(getSaturnComponent())
        .bindInstance(engine);
}

TEST(Saturn, start) {
    MockEngine engine;
    EXPECT_CALL(engine, start()).Times(1);

    Injector<Car> injector = getTestCarComponent((Engine *) &engine);
    Car *car = injector.get<Car *>();

    car->start();

    // make other assertions and expectations
}

This fails to compile with No explicit binding was found for C, and C is an abstract class (so even if it has a C::Inject annotation it's ignored). in the mock_engine class. Any pointers here?

Thanks for any assistance you can give,
James

poletti-marco added a commit that referenced this issue Aug 28, 2016
…reporting an obscure error later on.

See issue #25.
@poletti-marco
Copy link
Contributor

TL;DR: use bindInstance(*engine) and it compiles.

You're calling bindInstance(engine) but engine is an Engine* and bindInstance() takes a reference. Fruit should really give you a better error message in this case though, it was very unclear from the message. I've now submitted a fix (that will be in the next Fruit release) to report the following error instead:

test_saturn.cpp: In function ‘fruit::Component<Car> getTestCarComponent(Engine*)’:
test_saturn.cpp:15:29: error: use of deleted function ‘void fruit::PartialComponent<Bindings>::bindInstance(C*) [with C = Engine; Bindings = {fruit::impl::InstallComponent<fruit::Component<fruit::Required<Engine>, Car> >}]’
         .bindInstance(engine);
                             ^
In file included from /home/marco/projects/fruit/include/fruit/fruit.h:28:0,
                 from test_saturn.cpp:2:
/home/marco/projects/fruit/include/fruit/component.h:216:8: note: declared here
   void bindInstance(C* p) = delete;
        ^

So, obligatory:

Any pointers here?

Yes, one too many in fact :-)

@durandj
Copy link
Author

durandj commented Aug 28, 2016

Well that was a silly mistake I created for myself. Thanks for the
"pointer" ;)

On Aug 28, 2016 09:40, "poletti-marco" notifications@github.com wrote:

TL;DR: use bindInstance(*engine) and it compiles.

You're calling bindInstance(engine) but engine is an Engine* and
bindInstance() takes a reference. Fruit should really give you a better
error message in this case though, it was very unclear from the message.
I've now submitted a fix (that will be in the next Fruit release) to report
the following error instead:

test_saturn.cpp: In function ‘fruit::Component getTestCarComponent(Engine_)’:
test_saturn.cpp:15:29: error: use of deleted function ‘void fruit::PartialComponent::bindInstance(C_) [with C = Engine; Bindings = {fruit::impl::InstallComponentfruit::Component<fruit::Required<Engine, Car> >}]’
.bindInstance(engine);
^
In file included from /home/marco/projects/fruit/include/fruit/fruit.h:28:0,
from test_saturn.cpp:2:
/home/marco/projects/fruit/include/fruit/component.h:216:8: note: declared here
void bindInstance(C* p) = delete;
^

So, obligatory:

Any pointers here?

Yes, one too many in fact :-)


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#25 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AGpPjkwQqiN3bl349K_lDC3Dn-h5Z5b5ks5qkZ3ugaJpZM4JuQn_
.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants