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

Able to mock non-virtual functions? #232

Open
Zerophase opened this issue May 27, 2021 · 14 comments
Open

Able to mock non-virtual functions? #232

Zerophase opened this issue May 27, 2021 · 14 comments

Comments

@Zerophase
Copy link

Just seeing if this is able to mock non-virtual functions. Adding them to some of the classes I'm testing has performance penalties. Is there any means of testing them with this framework, without having to litter everything with templates?

@rollbear
Copy link
Owner

It depends on what you mean. If you mean, to hijack an existing member function for the purposes of testing, then that is not possible. Trompeloeil generates valid C++ code and does not play tricks under the hood. If that kind of trickery is important to you, you may want to look into HippoMocks instead. If, on the other hand, you mean to create a concrete type with mock-implementations of non-virtual functions, then sure. This is perfectly valid. It's up to you how to use it without causing ODR violations, but with some care it's possible.

struct my_struct
{
    MAKE_MOCK1(mock_func, int(int));
};

@Zerophase
Copy link
Author

@rollbear Wait would just prefixing functions with TEST_VIRTUAL, and placing virtual for tests work?

@rollbear
Copy link
Owner

I don't think I understand what you want to achieve. The example above creates a non-virtual function named mock_func. The only reason mocking functions from interfaces become virtual is because they override a virtual function from the interface.

struct base
{
    virtual int virtual_func() = 0;
};

struct implementation : base
{
    MAKE_MOCK0(virtual_func, int()); // is virtual because override from base
    MAKE_MOCK0(non_virtual_func, int()); // is not virtual
};

@Zerophase
Copy link
Author

Zerophase commented May 29, 2021

I mean something like this. eranpeer/FakeIt#75

In other words does the function need to be pure virtual?

fseam looks like an interesting alternative. Sadly, it looks like an abandoned project.

@rollbear
Copy link
Owner

Nothing needs to be virtual, as I have shown in the two examples above. It's a very common use case that a function is, but there's no such need. In fact, it's more work to make a function virtual.

@MickaelOnTheWave
Copy link

The example shown is using the framework to create a new non-virtual function. But if the initial situation has no virtual function :

struct base
{
    int non_virtual_func() {};
};

struct implementation : base
{
    MAKE_MOCK0(non_virtual_func, int());
};

This is failing for me : in the test the original base::func() function is called instead of implementation::func().

Do you know how to mock such a function with your framework without having to make every mockable member function virtual?

@rollbear
Copy link
Owner

rollbear commented Nov 1, 2022

You can obviously not do that via virtual dispatch, since that requires that the base class has the necessary functions in the vtable. Those are the rules of the language.

You can do it via various duck-typing techniques, for example accepting implementation as a template type instead.

@Zerophase
Copy link
Author

Couldn't you just use a raw pointer, and just use a macro to bit shift the memory to a mock object for calls?

I think that would enable testing of non-virtual functions with mock calls. If I remember correctly, Hippomocks does not work anymore. Your project is better designed than everyone else it just lacks one feature a lot of people need.

@rollbear
Copy link
Owner

rollbear commented Nov 3, 2022

The word "just" carries a lot of weight in that sentence. That is undefined behaviour that I absolutely do not want to maintain across multiple compilers and operating systems. You can, of course, ask @dascandy to resurrect Hippomocks, if you want to.

@dascandy
Copy link

dascandy commented Nov 4, 2022

If I remember correctly, Hippomocks does not work anymore.

I was not aware of that @Zerophase ? Can you elaborate? Any specific compiler or configuration that broke?

Note that Hippomocks also does not allow mocking arbitrary nonvirtual member functions. You can mock any static function or global function though, and yes that does a lot of non-C++-defined behavior. There are quite some limitations to that.

@mehditlili
Copy link

I think there is some miunderstanding here.

Say you are trying to mock some class from an existing codebase for testing purposes. That class has only non virtual methods and you cannot modify the codebase.

Would the right approach be to clone that class declaration from its respective header and declare all methods as virtual?

And if you are allowed to modify the codebase, would adding TEST_VIRTUAL in front of the function declarations be preferred?

@Zerophase
Copy link
Author

That would be ideal. Some type of macro in front that just makes it virtual for tests. No, idea if there's any edge cases where stuff can break from that.

@Zerophase
Copy link
Author

If I remember correctly, Hippomocks does not work anymore.

I was not aware of that @Zerophase ? Can you elaborate? Any specific compiler or configuration that broke?

Was awhile back. I just know it did not successfully compile at the time. When I get back to working on my project I'll check.

@Mr-TTWang
Copy link

That would be ideal. Some type of macro in front that just makes it virtual for tests. No, idea if there's any edge cases where stuff can break from that.

That will be very convenient by this way. @Zerophase ☆( ̄▽ ̄)/$:*

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

6 participants