-
Notifications
You must be signed in to change notification settings - Fork 175
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
what if I need to use shared_ptr or unique_ptr of the mock object in my unittest #60
Comments
+1 I'm having trouble working out how to create a shared_ptr for a mocked object, I'm looking into creating a copy of the stack allocated mock object to a shared_ptr, but haven't worked out how to do it yet. |
I've attempted to create a shared_ptr with the line: however I get a compile error: |
just fake the destructor and pass the pointer to
|
Thanks, I used to use spying
But apparently, "fake the destructor" is much better. |
I'm still having trouble with the mock being released prematurely in my async test. I think I need to allocate the mock object on the heap rather than the stack, is there any way to do this?
I will attempt to use spying for now, thanks @xqian |
for me it works when I write (*mock) as in
|
Thanks @tnovotny . I needed to write the mock object code outside of my lambda which later returns the mock object, otherwise the mocked definitions are prematurely released.
|
In the end I ended up taking the spy approach so I don't have to mock every method in my virtual classes(interfaces). I created stubbed classes to mock via spy, if a method is called which isnt mocked it will throw an unmocked function runtime_error. |
" I created stubbed classes to mock via spy," can you share more specifically how you do this without mock every method in my virtual classes(interfaces)? |
I think that the Mock interface could benefit having a method that returns std::shared_tr<C> operator()() {
return std::shared_ptr<C>(get(), [] (C*) { /* No op custom deleter */ });
} |
@Teemu-Santio 's solution is the correct one, so far as I've found, and it's the only one that will prevent the memory from being freed (which, AFAIK a fake dtor won't do). I wound up writing a template function that accepts a Mock and infers the correct parameters to return a shared_ptr from a Mock using the method mentioned above. The same applies to unique_ptr as well (and the boost versions). |
In case someone wants to omit the template function: |
@eranpeer |
This issue can be closed because it never really was an issue. Personally I would not pollute the API with such trivial methods. |
In case someone is looking for a complete example of a way to handle objects that require mocking but are managed by a unique_ptr, I thought I'd post how I handled it. In our code base, a build is set to either include unit test code or not based on if a macro is defined. If this macro is defined, test code is included and a single unit test app is constructed that runs all tests (this is done with the doctest unit testing framework, which is a great framework, so be sure to check it out). For this example, we'll say the unit test macro is COMPILING_UNIT_TESTS.
Now, any code that has a A word of warning: Finally, note that there are other ways besides a functor to provide a unique_ptr with a custom deleter (e.g. you could use a lambda), but that the functor approach is generally the better way to go. See here for a discussion on this. |
@LossMentality I don't get it. What problem does this solve that |
@tnovotny
will fail with
somewhere deep in destructor of |
I think this information is crucial. I wasted an hour until I found this thread. The only solution that worked for me was: fakeit::Mock<Foo> fooStub;
auto pointerToFoo = std::shared_ptr<Foo>(&fooStub(), [](...) {}); I understand that you don't want to pollute the API with methods like this. But this should at least be part of https://github.com/eranpeer/FakeIt/wiki/Quickstart. Adding a section on how to deal with |
@Iqon thank you! I've been fighting with this issue repeatedly. Your solution works like a charm and I agree that it would be extremely useful to have it in the documentation and/or FAQ. |
In my case the solution for |
Could someone provide a code snippet with the issue? Because I can't reproduce it : https://godbolt.org/z/fTn66GhMK As I it's supposed to be fixed since 2015 : #10 |
I'm going backwards and forwards trying as many options as I can, but I can't seem to figure out a solution for Alas, the 'spying' solution doesn't work for us, because the interface is abstract. |
Could you provide a code sample ? Because in the example I showed above I replaced |
Yeah... I'm starting to come to the conclusion this is fundamentally incompatible for that reason, but here's some test code anyways that is roughly equivalent to what I'd be testing: #include <map>
#include <memory>
class ITestInterface
{
public:
ITestInterface() {}
virtual ~ITestInterface() {}
virtual double getResult() = 0;
};
class TestContainer
{
public:
TestContainer() {}
void addItem(int key, std::unique_ptr<ITestInterface> item)
{
lookup.emplace(key, std::move(item));
}
double getItemResult(int key)
{
return lookup[key]->getResult();
}
private:
std::map<int, std::unique_ptr<ITestInterface>> lookup;
}; There doesn't seem to be any means to construct a unique_ptr to a stubbed ITestInterface that can be used in addItem() without segfaulting or using elaborate workarounds that redefine unique_ptr like LostMentality. Without any better ideas, I'm planning to just manually implement a fake version of my interface that itself stores a reference to a stub and proxies calls to it. |
It doesn't segfault for me : https://godbolt.org/z/obMjnYKv3 Could you provide a code sample that segfault ? |
It does if you do roughly the same thing in a catch2 unit test. SCENARIO("Example Unit Test")
{
GIVEN("TestContainer instance")
{
TestContainer testContainer;
WHEN("addItem() is called to add an item")
{
Mock<ITestInterface> mock;
Fake(Dtor(mock));
When(Method(mock, getResult)).AlwaysReturn(2.5);
testContainer.addItem(5, std::unique_ptr<ITestInterface>(&mock.get()));
THEN("getItemResult on the same item will return 2.5")
{
REQUIRE(2.5 == testContainer.getItemResult(5));
}
}
}
} Here's the complete example, including catch and fakeit headers for local compile. I'm not really much of a compiler explorer user to figure out the correct way to build catch with it. My build command was:
|
It's because the mock is destroyed before testContainer (and thus before unique_ptr call the destructor of the mock). Just move the instantiation of the mock higher so its destructor is called after the one of testContainer and it should be fine. |
🤦 Mock<ITestInterface> mock;
TestContainer testContainer; |
There is a problem with unique_ptr and shared_ptr on windows when there is a virtual destructor. There is a specific workaround for shared_ptr, and a general work around but here is a proposed general fix: |
Since #289 fixed a bug with destructors on MSVC (in FakeIt 2.3.1) I'm confident that this issue is now definitely fixed on every platforms supported by FakeIt, so I'll close it. Don't hesitate to create a new one if you think it's not fixed for your configuration. |
The code is like this
struct Paint
{
Paint(shared_ptr p_pen) :m_pen(p_pen) {};
void RePain()
{
m_pen->Do();
}
shared_ptr m_pen;
}
struct IPen
{
virtual Do() =0;
}
When I testing Paint, I want to pass a mocked IPen into Paint.
But how can I pass the shared_ptr of IPen into Paint?
If I can change the design to make Paint to have reference on IPen might be better. But If there a solution that I can use mock a shared_ptr?
The text was updated successfully, but these errors were encountered: